2014-01-30 146 views
1

我有一個C#類&方法,我已經蒸餾至無所事事,但分配的COM對象和執行工藝外的一個C++ COM服務器的調用。COM客戶端將無法訪問C++ COM服務器

eFilm.IEFilm eFilmInterface = (eFilm.IEFilm)Activator.CreateInstance(Type.GetTypeFromProgID("EFilm.Document", true)); 
eFilmInterface.oleCloseAllWindows(); 

當我在命令行上以我的登錄用戶身份執行此代碼時,它將生成不足的特權錯誤。如果我然後提升它(或運行一個高架的外殼),它工作正常。它正試圖訪問的COM服務器是一個獨立的應用程序,我登錄到我的用戶後開始。

我,而不是試圖執行在Windows服務這同樣的動作。該服務是VS2012 C#windows服務模板的基本實現,我標記爲.Net 4.0和任何CPU或x86(兩者都失敗)。我試圖在服務的的OnStart實施過程中STA線程上調用(儘管它呈現在OnStart中運行同樣的問題()方法本身):

protected override void OnStart(string[] args) 
{ 
    var staThread = new Thread(this.OnStartSTA); 
    staThread.SetApartmentState(ApartmentState.STA); 
    staThread.Start(); 
} 

private void OnStartSTA(object threadState) 
{ 
    eFilm.IEFilm eFilmInterface = (eFilm.IEFilm)Activator.CreateInstance(Type.GetTypeFromProgID("EFilm.Document", true)); 
    eFilmInterface.oleCloseAllWindows(); 
} 

的的CreateInstance()調用失敗,但有以下例外:

System.Runtime.InteropServices.COMException (0x80080005): Retrieving the COM class factory for component with CLSID {C8CF03E4-FD1F-11D3-8C03-0080C8D3C5D3} failed due to the following error: 80080005 Server execution failed (Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE)). 
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) 
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) 
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) 
at System.Activator.CreateInstance(Type type, Boolean nonPublic) 
at System.Activator.CreateInstance(Type type) 

我已經嘗試將活動會話中的同一用戶更改爲本地系統的服務帳戶。我犯了同樣的錯誤。我已經有服務驗證CLSID是否存在於其註冊表視圖中。我在服務器日誌中找不到任何錯誤(儘管我沒有代碼或調試符號)。 Windows應用程序日誌顯示完全相同的錯誤(可能是因爲它通過鏈式拋出全部通過)。我嘗試將GetTypeFromProgID切換到遠程版本並引用localhost,但它會生成相同的錯誤。

此外,如果我使用命令行版本的應用程序,並通過NSSM生成服務包裝,我會得到完全相同的錯誤。

我不知道什麼是錯的,我也不對如何繼續調試一個非常好的計劃。關於我能想到的所有問題都是用戶上下文的問題,但這似乎是COM應該能夠做到的。另一種選擇是服務器註冊中缺少一些關鍵信息。 I already had issues with that earlier在這個過程中。

編輯:

經過進一步調查,似乎調用企圖COM服務器的結果啓動在任何用戶上下文服務器的新副本服務在,不活躍用戶身份運行上下文。我試圖模仿該用戶,但它沒有改變任何東西。如果我運行具有用戶憑據的服務,你只看到在任務管理器&進程資源管理器相同的用戶運行的應用程序的兩個副本。我懷疑這與服務器的構建或配置有關。

有一件事我覺得有趣,即使我開始與本地系統服務冒充COM調用作爲活動的用戶,COM服務器被作爲啓動系統,而不是用戶。

EDIT2:

通過COM/DCOM設置翻轉,看起來像在DCOM的AppID有一個RunAS which lets you choose interactive user。我的服務器從未註冊過AppID部分。

我手動砍死在的AppID部分來的AppID和CLSID,但它似乎並沒有解決它。它仍然在服務的上下文中產生進程,儘管進程的大小不會增長到它通常所做的全部大小。

回答

0

好的,所以答案似乎是"RunAs" switch for AppID。由於我沒有這個服務器的AppID,我必須生成一個。我需要解決這個問題的步驟如下:

  1. 爲AppID生成一個新的GUID。啓動您的開發人員提示並鍵入guidgen.exe。這會帶來一個對話框。選擇「註冊表格式」選項並在某處複製此GUID。
  2. 調出一個文本編輯器並創建一個.reg文件以導入到註冊表中。您將需要如下所示的行。將YOUR_NEW_GUID替換爲#1中的GUID和SERVER_CLSID以及服務器的ProgID中的CLSID。

    Windows註冊表編輯器版本5.00

    [HKEY_LOCAL_MACHINE \ SOFTWARE \類\的AppID \ {YOUR_NEW_GUID}] 「運行方式」= 「交互式用戶」

    [HKEY_LOCAL_MACHINE \ SOFTWARE \類\ CLSID \ {SERVER_CLSID }] 「的AppID」= 「{E33A55D3-6743-4F3B-AA90-BB07B9BA3836}」

  3. 如果操作系統是64位和服務器是32位應用程序,然後執行經由32位註冊表編輯器\ Windows \ syswow64 \ regedit.exe file.reg將file.reg更改爲步驟#2中的文件。這將正確安裝在各個syswow64位置。否則,只是使用器regedit.exe file.reg

從理論上講,這應該這樣做。您現在應該能夠確認這是通過以管理員身份執行oleview.exe而發生的。如果你有同樣的問題,你需要檢查是否已經有一個AppID註冊到該服務器,然後再創建一個AppID。如果是這樣,你可以使用oleview並在那裏編輯它。

在oleview.exe中,在對象類>所有對象下找到您的組件。選擇這個,在右側的工作窗口中選擇「Implementation」選項卡,你現在應該看到你生成的新的AppID GUID。在「激活」選項卡下,您應該看到「啓動爲交互式用戶」選中。