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 元件,  底層會有此一問題。


沒有留言:

張貼留言

Ubuntu 中編譯 FFMPEG 產生. so

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