ClickOnce 的 ApplicationDeployment.CheckForUpdate 呼叫次數限制

最近於一個使用 clickonce 部署的 wpf 程式發生了一次如下的 COMException&nbsp:
System.Runtime.InteropServices.COMException (0x80070511): 服務正常運作所需的權限不存在於此服務帳戶設定中。 您可以使用 Microsoft Management Console (MMC) 的服務嵌入式管理單元 (services.msc) 及本機安全性設定 MMC 嵌入式管理單元 (secpol.msc) 來檢視服務設定及帳戶設定。 (發生例外狀況於 HRESULT: 0x80070511)
   於 System.Deployment.Internal.Isolation.IStore.GetAssemblyInformation(UInt32 Flags, IDefinitionIdentity DefinitionIdentity, Guid& riid)
   於 System.Deployment.Internal.Isolation.Store.GetAssemblyManifest(UInt32 Flags, IDefinitionIdentity DefinitionIdentity)
   於 System.Deployment.Application.ComponentStore.GetAssemblyManifest(DefinitionIdentity asmId)
   於 System.Deployment.Application.ComponentStore.GetSubscriptionStateInternal(DefinitionIdentity subId)
   於 System.Deployment.Application.SubscriptionStore.GetSubscriptionStateInternal(SubscriptionState subState)
   於 System.Deployment.Application.ApplicationDeployment.CreateDeploymentManager()
   於 System.Deployment.Application.ApplicationDeployment.CheckForDetailedUpdate(Boolean persistUpdateCheckResult)

之後接連發生了許多次的 NullReferenceException:
System.NullReferenceException: 並未將物件參考設定為物件的執行個體。
   於 System.Deployment.Application.DeploymentManager.BindCoreWithAppId(Boolean blocking, FileStream& refTransaction, String& productName)
   於 System.Deployment.Application.DeploymentManager.BindCore(Boolean blocking, TempFile& tempDeploy, TempDirectory& tempAppDir, FileStream& refTransaction, String& productName)
   於 System.Deployment.Application.DeploymentManager.Bind()
   於 System.Deployment.Application.ApplicationDeployment.CheckForDetailedUpdate(Boolean persistUpdateCheckResult)

程式的每隔一段時間呼叫 ApplicationDeployment.CheckForUpdate 檢查是否有新的版本,若有的話則進行更新
try
{
    if (ApplicationDeployment.IsNetworkDeployed)
    {
        // 取得目前使用者的版本資訊
        ApplicationDeployment deployment = ApplicationDeployment.CurrentDeployment;

        Console.WriteLine(string.Format("第{0}次檢查更新", ++this.chkUpdCnt));
        // 比對伺服器上的版本
        if (deployment.CheckForUpdate(false))
        {
            deployment.UpdateAsync();//--更新ClickOnce
        }
    }
}
catch (Exception ex)
{
    Logger.FileLog.Error(string.Format("第{0}次檢查更新失敗{1}", this.chkUpdCnt, ex));
}
百思不得其解,網路上找了一下,於 MSDN 的某篇文章 發現也有人遇到同樣的狀況,也得到了解答。

原來是每次呼叫 CheckForDetailedUpdate 時,系統會建立一個新的 DeploymentManager 的物件,然後將它與 多種 stored subscription state 作繫結。每一種 state  從 store 取出時,會呼叫 GetDeploymentProperty 函式,過程中會建立一個結構 如下:

dfshim!_TSHANDLE_TYPE_DEFINITION_DESCRIPTION
   +0x000 Flags            : 0
   +0x008 TypeName         : 0x00000000`00afe800  "IsolatedFilesystem"
   +0x010 InstanceSize     : 8
   +0x018 HeaderSize       : 0x28
   +0x020 InstanceCount    : 0xfffe
   +0x028 TypeContext      : (null)
   +0x030 Allocator        : 0x00000642`ff538180     unsigned char  dfshim!tsh_DefaultTypeAllocator+0
   +0x038 Deallocator      : 0x00000642`ff5381e0     void  dfshim!tsh_DefaultTypeDeallocator+0
   +0x040 Constructor      : 0x00000642`ff4f3d80     unsigned char  dfshim!Windows::TypeSafeHandle::Provider::Rtl::CTsObject::Constructor+0
   +0x048 Destructor       : 0x00000642`ff4f3e70     void  dfshim!Windows::TypeSafeHandle::Provider::Rtl::CTsObject::Destructor+0
   +0x050 TypeId           : 5
   +0x058 CriticalSection  : _RTL_CRITICAL_SECTION
   +0x080 Objects          : BCL::CDeque<_tshandle_instance_header>
   +0x0a8 Table            : 0x00000000`00b21cd2 Void
   +0x0b0 MaxHandles       : 0xffff
   +0x0b8 MaxInstances     : 0xffff

其中的 InstanceCount 值為 0xfffe,而 MaxInstances 值為 0xffff。
推估是每次建立 結構時 InstanceCount 會加1,當 InstanceCount 的值等於 MaxInstances  時,就會引發此一錯誤。

目前測試,於 windows 7 執行 呼叫了 CheckForDetailedUpdate  8 百多次 會發生此一問題,於 Xp、8、10、2008、2012 測試 正常。推估底層是呼叫 了 Com 元件,  底層會有此一問題。


c# 的 DateTime.Kind 屬性

緣由:
  C# 的 DateTime 是很常用的結構,但在下對它並不十分了解。
頂多存取到它的年、月、日、時、分、秒來使用,因此想多了解一下關於 DateTime 結構的使用方法。
於 DateTime 的其中一個建構函式:
public DateTime(
 int year,
 int month,
 int day,
 int hour,
 int minute,
 int second,
 DateTimeKind kind
)
除了常用的 年、月、日、時、分、秒外,可以另外指定 DateTimneKind  參數。
若未指定 kind 的話,預設值為 System.DateTimeKind.Unspecified.

MSDN 關於 DateTime.Kind  屬性,有一些相關的說明與範例
主函式如下:
static void Main(string[] args)
{
    // 取得目前的本地端時間
    DateTime localNow = DateTime.Now;

    // 取得目前的國際標準時間
    DateTime utcNow = DateTime.UtcNow;
    Display("UtcNow:", utcNow);
    Display("LocalNow:", localNow);

    // 將本地端時間的 Kind 轉為 utc,轉換後兩者的小時一樣
    DateTime myDt = DateTime.SpecifyKind(localNow, DateTimeKind.Utc);
    ConvertAndDisplay("Utc:", myDt);

    // 將本地端時間的 Kind 轉為 local, 轉換後兩者的小時一樣
    myDt = DateTime.SpecifyKind(localNow, DateTimeKind.Local);
    ConvertAndDisplay("Local:", myDt);

    // 將本地端時間的 Kind 轉為 unspecified, 轉換後兩者的小時一樣
    myDt = DateTime.SpecifyKind(localNow, DateTimeKind.Unspecified);
    ConvertAndDisplay("Unspecified:", myDt);

    Console.ReadKey();
}
Display 函式的功能是顯示時間
public static void Display(string title, DateTime inputDt)
{
    Console.WriteLine("{0}{1}, kind={2}", title, inputDt.ToString(DatePatt), inputDt.Kind);
}
ConvertAndDisplay函式負責將輸入的時間轉換為本地時間與世界標準時間,然後依序列印出來, 這裡比較要注意的是若
  1. inputDt.Kind 為 DateTimeKind.Utc 的話,執行 ToLocalTime 會轉換為對應的本地端時間;
  2. inputDt.Kind 為 DateTimeKind.Local 的話,執行 ToLocalTime 並不會轉換;
  3. inputDt.Kind 為 DateTimeKind.Unspecified 的話,執行 ToLocalTime 的過程中,inputDt 會被視為世界標準時間來轉換;
相對的若
  1. inputDt.Kind 為 DateTimeKind.Utc 的話,執行 ToUniversalTime 會轉換為對應的世界標準時間;
  2. inputDt.Kind 為 DateTimeKind.Local 的話,執行 ToUniversalTime 並不會轉換;
  3. inputDt.Kind 為 DateTimeKind.Unspecified 的話,執行 ToUniversalTime 的過程中,inputDt 會被視為本地端時間來轉換
public static void ConvertAndDisplay(string title, DateTime inputDt)
{
    Display(title, inputDt);      
    DateTime localTime = inputDt.ToLocalTime();
    Display("    ToLocalTime:", localTime);

           
    DateTime utcTime = inputDt.ToUniversalTime();
    Display("    ToUtcTime:", utcTime);
 }

執行結果如下:
 

結論: 只指定年、月、日、時、分、秒的 DateTime 建構函式,其 Kind 屬性預設為 Unspecified。若呼叫 ToLocalTime 時,本身會被視為 Utc Time; 相對的,若呼叫 ToUtcTime 時,本身會被視為 Local Time.

Ubuntu 中編譯 FFMPEG 產生. so

參考連結如下:   https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu cd ~/ffmpeg_sources && \ wget -O ffmpeg-snapshot.tar.bz2 https:/...