玩转Windows服务系列——无COM接口Windows服务启动失败原因及解决方案

简介: 原文:玩转Windows服务系列——无COM接口Windows服务启动失败原因及解决方案将VS创建的Windows服务项目编译生成的程序,通过命令行 “服务.exe -Service”注册为Windows服务后,就可以通过服务管理器进行管理了。
原文: 玩转Windows服务系列——无COM接口Windows服务启动失败原因及解决方案

将VS创建的Windows服务项目编译生成的程序,通过命令行 “服务.exe -Service”注册为Windows服务后,就可以通过服务管理器进行管理了。

问题

通过服务管理器进行启动的时候,发现服务无法启动,提示错误

无Com接口服务启动失败

由于程序代码是由VS的项目模板生成的,生成后直接编译为Debug版,然后通过命令行进行注册,期间并没有修改过任何代码。

难道是只有Release版本才能通过服务管理器启动吗。于是将Release版注册为服务,通过服务管理器启动,仍然会报同样的错误。

由于服务比较特殊,应该会在Windows的事件管理器中留下日志,经查看,日志为

服务启动失败系统事件

可以看到系统日志中并无异常。

问题还不只如此,当Debug版本通过 RegServer 注册后,程序也是启动后立即停止。

既然如此,那就开始使用神器——单步调试。

启动失败原因

Window服务程序启动后,会在WinMain方法中调用一个Run方法

HRESULT Run(_In_ int nShowCmd = SW_HIDE) throw()
{
    HRESULT hr = S_OK;

    T* pT = static_cast<T*>(this);
    hr = pT->PreMessageLoop(nShowCmd);

    // Call RunMessageLoop only if PreMessageLoop returns S_OK.
    if (hr == S_OK)
    {
        pT->RunMessageLoop();
    }

    // Call PostMessageLoop if PreMessageLoop returns success.
    if (SUCCEEDED(hr))
    {
        hr = pT->PostMessageLoop();
    }

    ATLASSERT(SUCCEEDED(hr));
    return hr;
}

而Run方法中会调用pT->RunMessageLoop()方法,来进行一个While循环,从而阻止WinMain方法返回,造成程序结束。

经过调试,发现执行时,pT->PreMessageLoop 方法返回了S_FALSE,由于RunMessageLoop方法前有一个判断,所以此方法没有执行,从而造成程序启动便立即停止。

而真正造成PreMessageLoop方法返回S_FALSE的原因是

hr = pT->RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);

调用RegisterClassObjects方法,返回了S_FALSE,而RegisterClassObjects方法又调用了AtlComModuleRegisterClassObjects方法,实际上是在注册Com相关的东西,而由于程序是由VS创建的默认代码编译的,并未添加任何Com接口,所以就会返回S_FALSE,即注册失败。

解决方案

找到了问题的原因了,那么也就相对好解决了。

既然程序中,并没有使用到Com相关的东西,那么就干脆跳过RegisterClassObjects方法的调用。

由于PreMessageLoop方法中通过宏_ATL_NO_COM_SUPPORT,可以决定是否跳过RegisterClassObjects的调用,所以只需要在预处理器中或者代码中定义这个宏即可。

代码如下

#define _ATL_NO_COM_SUPPORT

或者通过预处理器来定义

无Com接口的服务项目预处理器

系列链接

玩转Windows服务系列——创建Windows服务

玩转Windows服务系列——Debug、Release版本的注册和卸载,及其原理

玩转Windows服务系列——无COM接口Windows服务启动失败原因及解决方案

玩转Windows服务系列——服务运行、停止流程浅析

玩转Windows服务系列——Windows服务小技巧

玩转Windows服务系列——命令行管理Windows服务

 
目录
相关文章
|
1月前
|
Linux Shell Windows
通过Linux挂载Windows端NFS服务实现板端Linux传输文件到PC
通过Linux挂载Windows端NFS服务实现板端Linux传输文件到PC
|
1月前
|
存储 安全 数据安全/隐私保护
Windows部署WebDAV服务并映射到本地盘符实现公网访问本地存储文件
Windows部署WebDAV服务并映射到本地盘符实现公网访问本地存储文件
269 0
|
2月前
|
Java Unix 应用服务中间件
使用java service wrapper把windows flume做成服务
使用java service wrapper把windows flume做成服务
|
2月前
|
Windows
修改Windows服务的配置
修改Windows服务的配置
|
26天前
|
Shell Windows
Windows服务器 开机自启动服务
Windows服务器 开机自启动服务
14 0
|
21天前
|
安全 Windows
安装MyEclipse遇到错误提示 Failed to find a Main Class in “C:Windows\Temp\“时的解决方案
安装MyEclipse遇到错误提示 Failed to find a Main Class in “C:Windows\Temp\“时的解决方案
23 1
|
4天前
|
网络协议 安全 测试技术
Windows安装禅道系统结合Cpolar实现公网访问内网BUG管理服务
Windows安装禅道系统结合Cpolar实现公网访问内网BUG管理服务
|
1月前
|
Windows
windows server 2019 安装NET Framework 3.5失败,提示:“安装一个或多个角色、角色服务或功能失败” 解决方案
windows server 2019 安装NET Framework 3.5失败,提示:“安装一个或多个角色、角色服务或功能失败” 解决方案
104 0
|
1月前
|
存储 Windows
windows server 2019 云服务器看不见硬盘的解决方案
windows server 2019 云服务器看不见硬盘的解决方案
|
1月前
|
弹性计算 安全 数据安全/隐私保护
远程桌面连接Windows实例,提示“为安全考虑,已锁定该用户账户,原因是登录尝试或密码更改尝试过多”错误解决方案
远程桌面连接Windows实例,提示“为安全考虑,已锁定该用户账户,原因是登录尝试或密码更改尝试过多”错误解决方案
175 0