2011-04-28 33 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