2011-04-28 35 views
2

我有一個ATL COM服務exe(MyService.exe),它編譯並運行良好。如果我安裝此服務(通過MyService.exe/Service),它已成功安裝到SCM中。我可以通過SCM啓動服務,它可以在LOCALSYSTEM帳戶下正常運行。CoCreateInstance不啓動或連接到ATL COM服務

當我嘗試創建由服務定義的COM類的實例時出現問題。我的測試工具的應用程序(MyServiceTest.exe),調用以下:

::CoInitialize(NULL); 
::CoInitializeSecurity(NULL, 
         NULL, 
         NULL, 
         NULL, 
         RPC_C_AUTHN_LEVEL_PKT, 
         RPC_C_IMP_LEVEL_IMPERSONATE, 
         NULL, 
         EOAC_NONE, 
         NULL); 
ATL::CComPtr<IMyServiceInterface> pInterface; 
HRESULT hr = CoCreateInstance(CLSID_MyServiceInterface, NULL, CLSCTX_LOCAL_SERVER, IID_IMyServiceInterface, reinterpret_cast<void**>(&pInterface)); 

在調用CoCreateInstance的,幾個不同的事情發生,這取決於如何安裝MyService.exe:

  1. 爲MyService使用/ Service命令行安裝.exe:
    MyServiceTest.exe調用CoCreateInstance,並調用MyService WinMain。隨後調用CAtlServiceModuleT :: Start,這會確定可執行文件已使用命令行選項'-Embedding'啓動。它確定它作爲服務安裝,並且像這樣調用:: StartServiceCtrlDispatcher()。此調用失敗,錯誤代碼爲1063(ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)。根據MS:

「如果程序正在運行作爲控制檯應用程序,而不是作爲一種服務將返回此錯誤。如果該方案將作爲控制檯應用程序以進行調試運行,結構是這樣的返回此錯誤時不會調用服務特定的代碼。「

調用失敗,MyService.exe退出,並且CoCreateInstance調用超時。

  1. MyService.exe不是作爲服務安裝,而是通過註冊/ RegServer添加
    MyServiceTest.exe調用CoCreateInstance,併爲MyService WinMain函數被調用。 MyService.exe在登錄的用戶帳戶(不是LOCALSYSTEM)下實例化。可執行文件成功運行,但不作爲服務,這不是所需的行爲。儘管沒有作爲服務運行,CoCreateInstance()調用成功,我得到一個有效的接口指針,通過它可以調用MyService COM函數。

  2. MyService.exe沒有安裝爲服務,通過/ RegServer添加註冊,並已在運行
    MyServiceTest.exe調用CoCreateInstance(成功場景2例如啓動後),以及一個新的實例的MyService.exe實例化,再次在登錄的用戶帳戶下。對於每次對CoCreateInstance的調用都會繼續此行爲。

我期望的行爲是,我可以安裝MyService.exe作爲一種服務,而CoCreateInstance的將啓動服務器,或者連接到當前MyService.exe例如,如果該服務已在運行。據我所知,上面的代碼應該以這種方式行事。我錯過了什麼?

這似乎是服務在LOCALSYSTEM下運行,而簡單的RegServer替代方案在本地用戶下運行似乎是相關的,但我不確定是否這是問題。

服務端調用CoInitializeSecurity是:

HRESULT hr = CoInitializeSecurity(0, 
            -1, 
            0, 
            0, 
            RPC_C_AUTHN_LEVEL_PKT, 
            RPC_C_IMP_LEVEL_IMPERSONATE, 
            0, 
            EOAC_NONE, 
            0); 

我在做什麼錯?

P.S. MyService.exe一旦啓動就不應退出,因爲它包含等待外部信號的Run()函數中的WaitForSingleObject()(它也在OnStop()中設置,因此SCM可以暫停服務)。這就是爲什麼MyService.exe在MyServiceTest.exe完成後仍然存在。這是期望的行爲(對於服務來說,它應該像運行一樣)。

回答

1

事實證明,罪魁禍首是服務的註冊方式。爲了一類,推出它的控制應用程序作爲服務,控制應用程序需要將條目添加到註冊表中,因此被認爲是本地服務器,即:

(MyService.rgs)

HKCR 
{ 
    NoRemove AppID 
    { 
     ForceRemove {6E5B1E7E-3340-4553-A356-76F1C3543452} = s 'MyService' 
     { 
      val LocalService = s 'MyService' 
      val ServiceParameters = s '-Service' 
     } 

     'MyService.EXE' 
     { 
      val AppID = s {6E5B1E7E-3340-4553-A356-76F1C3543452} 
     } 
    } 
} 

其中的AppID在MyService.rgs中指定。

這導致在註冊表中的以下佈局:

HKCR 
    AppID 
     {6E5B1E7E-3340-4553-A356-76F1C3543452} (Contains LocalService, ServiceParameters REG_SZ's) 
     MyService.EXE (Contains AppID REG_SZ) 
    CLSID 
     {MyServiceInterface GUID} (Contains MyService.EXE AppID) 

相關鏈接:
LocalService value
LocalServer32 overload in CoClass CLSID
Specifying AppID for CLSID

1

原諒我,如果你已經覆蓋了這一點:

運行DCOMCNFG.EXE。

向下鑽取組件服務\計算機\我的電腦\ DCOM配置。

找到您的組件,右鍵單擊並激活「屬性」。

在「標識」選項卡中,確保COM組件配置爲以與運行服務的標識相同的標識運行。

+0

感謝了上DCOMCNFG頭。這是我第一次真正進入COM,因此我不知道它。該組件設置爲「啓動用戶」。在身份下。我假設我想將它設置爲「系統帳戶」,但是這是灰色的(這看起來是錯誤的)。在常規選項卡下,應用程序類型被列爲本地服務器。我會認爲這應該是本地服務? – 2011-04-28 05:18:38