CoCreateInstance无法启动或连接到ATL COM服务

时间:2011-04-28 04:38:46

标签: c++ visual-studio-2010 com windows-services atl

我有一个ATL COM服务exe(MyService.exe),它编译并运行正常。如果我安装此服务(通过MyService.exe / Service),它将成功安装到SCM中。我可以通过SCM启动服务,它在LOCALSYSTEM帐户下运行正常。

当我尝试创建服务定义的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. 使用/ Service命令行安装MyService.exe:
    MyServiceTest.exe调用CoCreateInstance,并调用MyService WinMain。然后调用CAtlServiceModuleT :: Start,它确定已使用命令行选项'-Embedding'启动可执行文件。它确定它是作为服务安装的,因此调用:: StartServiceCtrlDispatcher()。此调用失败,错误代码为1063(ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)。据MS说:
  2.   

    “如果程序作为控制台应用程序而不是作为服务运行,则会返回此错误。如果程序将作为控制台应用程序运行以进行调试,请构造它以便在不调用特定于服务的代码时返回此错误。“

    调用失败,MyService.exe退出,CoCreateInstance调用超时。

    1. MyService.exe未作为服务安装,但通过/ RegServer注册
      MyServiceTest.exe调用CoCreateInstance,并调用MyService WinMain。 MyService.exe在登录的用户帐户(不是LOCALSYSTEM)下实例化。可执行文件成功运行,但不是作为服务运行,这不是所需的行为。尽管没有作为服务运行,CoCreateInstance()调用成功,我得到一个有效的接口指针,通过它我可以调用MyService COM函数。

    2. MyService.exe未作为服务安装,通过/ RegServer注册,并且已在运行(例如在方案2中成功启动后)
      MyServiceTest.exe调用CoCreateInstance,并在登录的用户帐户下再次实例化MyService.exe的新实例。对CoCreateInstance的每次后续调用都会继续此行为。

    3. 我希望的行为是我可以将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可以暂停服务)。这就是MyServiceTest.exe完成后MyService.exe仍然存在的原因。这是期望的行为(对于服务,它应该运行它)。

2 个答案:

答案 0 :(得分:1)

如果您已经涵盖了这一点,请原谅我:

运行DCOMCNFG.EXE。

深入了解组件服务\计算机\我的电脑\ DCOM配置。

找到您的组件,右键单击并激活“属性”。

在“标识”选项卡中,确保将COM组件配置为在运行该服务的同一标识下运行。

答案 1 :(得分: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

相关问题