问题描述
我有一个ATL COM服务exe(MyService.exe),它编译和运行良好。如果我安装此服务(通过MyService.exe / Service),它会成功安装到SCM中。我可以通过SCM启动服务,它运行良好,在LOCALSYSTEM帐户下。
I have a ATL COM service exe (MyService.exe), which compiles and runs fine. If I install this service (via MyService.exe /Service), it is successfully installed into the SCM. I can start the service through the SCM and it runs fine, under the LOCALSYSTEM account.
我的问题出现,当我试图创建一个COM类的实例定义的服务。我的测试工具应用程序(MyServiceTest.exe)调用以下命令:
My problem arises when I attempt to create an instance of a COM class defined by the service. My test harness application (MyServiceTest.exe), calls the following:
::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的安装方式:
At the call to CoCreateInstance, a few different things happen, depending on how MyService.exe is installed:
- MyService.exe是使用/ Service命令行安装的:
MyServiceTest。 exe调用CoCreateInstance,并调用MyService WinMain。然后调用CAtlServiceModuleT :: Start,它确定可执行文件已使用命令行选项'-Embedding'启动。它确定它安装为一个服务,因此调用:: StartServiceCtrlDispatcher()。此调用失败,错误代码为1063(ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)。根据MS:
调用失败,MyService.exe退出,CoCreateInstance调用超时。
The call fails, MyService.exe exits, and the CoCreateInstance call times out.
-
MyService.exe未作为服务安装,但通过/ RegServer注册
MyServiceTest.exe调用CoCreateInstance,并调用MyService WinMain。 MyService.exe在登录的用户帐户(不是LOCALSYSTEM)下实例化。可执行文件成功运行,但不作为服务,这不是所需的行为。尽管没有作为服务运行,CoCreateInstance()调用成功,我得到一个有效的接口指针,通过它可以调用MyService COM函数。
MyService.exe is NOT installed as a service, but is registered via /RegServer
MyServiceTest.exe calls CoCreateInstance, and MyService WinMain is called. MyService.exe is instantiated under the logged in user account (not LOCALSYSTEM). The executable successfully runs, but not as a service, which is not the desired behaviour. Despite not running as a service, the CoCreateInstance() call succeeds, and I get a valid interface pointer through which I can call MyService COM functions.
MyService.exe未作为服务安装,通过/ RegServer注册,并且已在运行(例如在方案2中成功启动后)
MyServiceTest.exe调用CoCreateInstance,一个新的MyService.exe实例被实例化,再次在登录的用户帐户下。
MyService.exe is NOT installed as a service, is registered via /RegServer, and is already running (after successfully being started in scenario 2 for example)
MyServiceTest.exe calls CoCreateInstance, and a NEW instance of MyService.exe is instantiated, again under the logged in user account. This behaviour continues for every subsequent call to CoCreateInstance.
我希望的行为是我可以安装MyService.exe作为一个服务,CoCreateInstance将启动服务器,或者如果服务已在运行,则连接到当前的MyService.exe实例。据我所知,上面的代码应该这样的行为。我缺少什么?
My desired behaviour is that I can install MyService.exe as a service, and CoCreateInstance will start the server, or connect to the current MyService.exe instance if the service is already running. As far as I was aware, the above code should behave this way. What am I missing?
似乎事实是服务在LOCALSYSTEM下运行,而简单的RegServer替代在本地用户下运行可能是相关的,但我不确定如果这是问题。
It seems the fact that the service runs under LOCALSYSTEM while the simple RegServer alternative runs under the local user could be pertinent, but I'm not sure if this is the issue.
对CoInitializeSecurity的服务端调用是:
The service side call to CoInitializeSecurity is:
HRESULT hr = CoInitializeSecurity(0,
-1,
0,
0,
RPC_C_AUTHN_LEVEL_PKT,
RPC_C_IMP_LEVEL_IMPERSONATE,
0,
EOAC_NONE,
0);
我做错了什么?
PS MyService.exe不应该在启动时退出,因为它在Run()函数中包含一个WaitForSingleObject(),该函数等待外部信号(也在OnStop()中设置,因此SCM可以停止服务)。这就是为什么MyService.exe在MyServiceTest.exe完成后仍然存在的原因。
P.S. MyService.exe should not exit once started, as it contains a WaitForSingleObject() in the Run() function which is waiting on an external signal (which is also set in OnStop() so the SCM can halt the service). This is why MyService.exe persists after MyServiceTest.exe completes. This is desired behaviour (for a service, which is what it should be running as).
推荐答案
事实证明,罪魁祸首是如何注册服务。为了让一个类启动它的控制应用程序作为服务,控制应用程序需要添加条目到注册表中,因此它被识别为本地服务器,即:
It turns out the culprit was how the service was registered. In order for a class to launch it's controlling application as a service, the controlling application needs to add entries into the registry so it is recognised as a local server, i.e:
(MyService.rgs)
(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中指定。
The AppID of which is specified in MyService.rgs.
这将导致注册表中的以下布局:
This leads to the following layout in the registry:
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)
相关链接:
为CLSID指定AppID a>
Pertinent links:
LocalService value
LocalServer32 overload in CoClass CLSID
Specifying AppID for CLSID
这篇关于CoCreateInstance不启动或连接到ATL COM服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!