VS2005 WINDOWS 服务体验

udpcn 2007-01-26 09:51:21

最近写的WINDOWS 服务,以前用VC6写过简单的服务。VC6 带的ATL 创建服务后,会生成一个继承于CcomModule 的类,并覆盖了START、STOP等(不记得了),只需在START、STOP里写相应的代码就行了。

现在已用VS2005,当然不用VC6了,VC8中的服务项目是基于.NET的,考虑.NET的性能对服务不合适,还是选择ATL8。但创建完项目就发现生成的类除了安全检测外什么也没有。

生成的类继承于CatlServiceModuleT的,在网上搜了一下CatlServiceModuleT,资料很少,例子较全的是一个英文网站上的,拿来一用出现一些问题,经过几天的摸索(先把作业叫了,再摸索的),大体弄清CatlServiceModuleT。

CatlServiceModuleT 用T* pT = static_cast<T*>(this) 来实现对子类函数的调用(如果子类重写了该函数)。我们可重写的函数有ParseCommandLine、Start、Run、PreMessageLoop、RunMessageLoop、PostMessageLoop、InitializeSecurity、OnStop、OnPause、OnContinue、OnShutdown、ServiceMain、Handler、RegisterAppId等。

网上一般是重写PreMessageLoop来做服务的开始工作,PostMessageLoop做结束工作。RegisterAppId 用来更改服务注册信息。

主线程有一个消息循环,它不做什么,只等收到消息推出程序。PreMessageLoop里面可以启动自己的线程,并进入服务处理循环。主线程和工作线程可用事件来交互,(如果多线程可能要用到互斥量、信号量),比如主线程OnStop的时候结束工作线程。

RegisterAppId 里面可以更改服务注册信息,主要用函数ChangeServiceConfig2来更改服务的描述,也就是在服务管理里面每个服务的描述,不改就为空。

结束工作可用PostMessageLoop,但我是直接在OnStop里面写的,也许主类中有要释放的资源才用PostMessageLoop。我的资源全在工作类中。

现在是一些问题:

1,调试:怎样才能在VS2005中调试。
看CatlServiceModuleT中的WinMain,检查输入参数有效就调用START。START先检测服务有没有注册过,没有注册的就直接返回退出。所以一定要先注册。检测到有注册就查看是否注册为LocalService(也就是 -Service),如果为LocalService就把_ServiceMain连接到SCM(服务管理器),但在调试模式下不能连接成功,或者必须由SCM来启动,要不它认为已启动。所以不能注册为服务,只能注册为RegSever(-RegSever)。调试完后,再注册为服务。如果只有在服务里面才出错,可用CatlServiceModuleT带的LogEvent 把调试信息写到windows事件里面。MSDN中讲可以服务进程连到VS2005我没试过,因为全在RegSever模式下解决了。

2,更改服务的启动模式。
没找到更改服务启动模式的方法。查看代码发现在CatlServiceModuleT的Install中写死的。
SC_HANDLE hService = ::CreateService(
hSCM, m_szServiceName, m_szServiceName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
szFilePath, NULL, NULL, _T("RPCSS\0"), NULL, NULL);

SERVICE_DEMAND_START表示手动在SCM启动。有个方法,在重写的RegisterAppId用ChangeServiceConfig修改,但看一下ChangeServiceConfig的参数,好多呀,太麻烦。加上我觉得写一个服务就应该自动启动,什么时候处理任务是服务的事,而且不想用了可以在SCM里禁用。所以我做了一个不道德的地方――把CatlServiceModuleT源程序改了。把SERVICE_DEMAND_START改为SERVICE_AUTO_START。
SC_HANDLE hService = ::CreateService(
hSCM, m_szServiceName, m_szServiceName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
szFilePath, NULL, NULL, _T("RPCSS\0"), NULL, NULL);
谁叫他不道德没流一个好的方法。当然你可以用ChangeServiceConfig,自己查一下。

3,暂停和继续,
我想用暂停和继续来实现配置的更新,因为不想改配置的时候,要停止服务,再启动,那样服务会断。还有就是用命名管道或全局消息让配置工具和服务通讯,但太麻烦,我只是想重新应有配置。
第一个问题,在SMC中暂停和继续的菜单是灰的。找了很久,找到::SetServiceStatus(m_hServiceStatus, &m_status) ,还好m_status是Public ,用m_status. dwControlsAccepted=m_status.dwControlsAccepted| SERVICE_ACCEPT_PAUSE_CONTINUE;搞定。
另一个问题,重写了OnPause但更本没进去。用LogEvent调试,发现CatlServiceModuleT的_Handler都没进去(LocalService就把_ServiceMain连接到SCM,_ServiceMain调用ServiceMain,ServiceMain中注册Handler为SCM处理函数,处理STOP、PAUSE等),_Handler 中是这样调用的((T*)_pAtlModule)->Handler(dwOpcode); 不知到_pAtlModule是指向谁的实例。我重写了Handler,就可以进来了。在自己的Handler中调用PAUSE,OnContinue后,就调用父类的Handler。


终于完成了,代码如下,工作线程没写出来。

class CNVSStoreServerModule : public CAtlServiceModuleT< CNVSStoreServerModule, IDS_SERVICENAME >
{
private:
CWorkThread * pWork; //工作类,没写出来。
public :
DECLARE_LIBID(LIBID_NVSStoreServerLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_NVSSTORESERVER, "{CF40AF29-C742-4D52-906C-5915A611F2D6}")
HRESULT InitializeSecurity() throw()
{
return S_OK;
}
void OnPauze() throw()
{
SetEvent(pWork->mServerStopEvent);
SetServiceStatus(SERVICE_PAUSED);
__super::OnPause();
}
void OnStop() throw()
{
SetEvent(pWork->mServerStopEvent);
WaitForSingleObject(pWork->mCanStopEvent,INFINITE);
__super::OnStop();
}
void Handler(DWORD dwOpcode) throw()
{
switch (dwOpcode)
{
case SERVICE_CONTROL_PAUSE:
OnPauze();
break;
case SERVICE_CONTROL_CONTINUE:
OnContinue();
break;
}
__super::Handler(dwOpcode);
}
CServiceStatus GetServiceStatus() throw()
{
return this->m_ServiceStatus;
}
void OnContinue( ) throw( )
{
SetServiceStatus(SERVICE_RUNNING);
__super::OnContinue();
}
HRESULT PreMessageLoop(int nShowCmd) throw()
{
m_status.dwControlsAccepted =m_status.dwControlsAccepted | SERVICE_ACCEPT_PAUSE_CONTINUE;
HRESULT hr = __super::PreMessageLoop(nShowCmd);
if (hr == S_FALSE) hr = S_OK; //要这句才能走下去
pWork=new CWorkThread();
return hr;
}
HRESULT RegisterAppId(bool bService = false) throw()
{
HRESULT hr = S_OK;
BOOL res = __super::RegisterAppId(bService);
if (bService)
{
if (IsInstalled())
{
SC_HANDLE hSCM = ::OpenSCManagerW(NULL, NULL, SERVICE_CHANGE_CONFIG);
SC_HANDLE hService = NULL;
if (hSCM == NULL)
hr = AtlHresultFromLastError();
else
{
hService = ::OpenServiceW(hSCM, m_szServiceName, SERVICE_CHANGE_CONFIG);
if (hService != NULL)
{
const int m_szServiceNameLen = 4096;
const int m_szServiceDescriptionLen = 2000;
WCHAR m_szServiceDescription[m_szServiceDescriptionLen]=L"你的服务描述";
SERVICE_DESCRIPTION sdBuf = {m_szServiceDescription};
res = ChangeServiceConfig2W(hService, SERVICE_CONFIG_DESCRIPTION, &sdBuf);
::CloseServiceHandle(hService);
}
else
hr = AtlHresultFromLastError();
::CloseServiceHandle(hSCM);
}

}
}
return hr;
}
};

CNVSStoreServerModule _AtlModule;

extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/, int nShowCmd)
{
return _AtlModule.WinMain(nShowCmd);
}
...全文
1353 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
wshcdr 2008-07-14
  • 打赏
  • 举报
回复
好长
firebolt2002 2008-07-11
  • 打赏
  • 举报
回复
其实我觉得重写RunMessageLoop 做服务的入口也是不错的选择,在事件循环之前做些必要的初始化工作,事件循环结束后可以做些清理工作。修改启动模式可以修改注册表完成。我发现写网络服务,服务无法加入防火墙例外列表里,必须手动添加或通过NetFw接口将该服务加入到防火墙例外中。不过ATL7对服务对象的包装确实不怎么样。还不如手动添加服务来的方便。
udpcn 2007-01-26
  • 打赏
  • 举报
回复
第一不知道不能连续发3次,上次没发完,删了重发。
西安瑞友信息技术资讯有限公司(简称瑞友公司)正式发布最新的瑞友天翼应用虚拟化系统5.2版本,新增Windows认证、HTTPS协议安全访问等全新功能,并对原有功能进行了全面优化。据悉,此次瑞友天翼应用虚拟化系统5.2版本升级主要围绕优化用户体验、提升用户办公效率,以此打造企业专属的信息管理平台。通过加入Windows认证、HTTPS协议安全访问等便捷的功能,瑞友天翼应用虚拟化系统将为用户带来更符合需求的使用体验。同时, 5.2版本还对集群安装、B/S单点登录、动态域名策略等现有功能进行了优化,力求为用户提供更优质、更全面、更便捷的服务。之前广受好评的智能移动客户端,也在此次版本升级中得到全面优化,iOS和Android移动客户端将更加稳定。 瑞友天翼应用虚拟化系统V5.2新增功能: 1、新增Windows认证功能 可实现Windows域用户直接导入天翼账户。 2、新增HTTPS协议安全访问功能 HTTPS是以安全为目标的HTTP通道,即HTTP下加入SSL层,用于安全的HTTP数据传输。 瑞友天翼应用虚拟化系统V5.2优化功能: 1、优化了集群安装,解决了副集群二次安装不能连接到主集群服务器的问题; 2、优化了B/S单点登录,新加了输入用户密码输入界面,更加便于客户理解和操作; 3、优化了动态域名策略,当一个集群有多个域名时,在agent客户端界面,检测性能最优的域名置于首条; 4、优化了Windows 2008操作系统客户端流量显示界面; 5、优化了智能移动终端,使iOS和Android移动客户端更加稳定。 自2005年正式发布以来,瑞友天翼应用虚拟化系统始终坚持以以用户的需求为导向,不断完善产品的性能,目前已经发布了数十个版本,而瑞友公司在不断提升产品的同时,以最新的企业级虚拟化技术、更丰富更优秀的企业信息化平台,保障企业在移动互联时代拥有持续领先的竞争力。 瑞友天翼应用虚拟化系统在业界早已拥有了很高的知名度和美誉度,北京市国土局、中国电信、中国移动、周大福、紫金矿业、龙门钢铁、宝钛集团等业界众多知名企业都使用瑞友天翼应用虚拟化系统作为企业信息管理平台。 瑞友公司:专业的虚拟化及云计算解决方案提供商,瑞友公司凭借雄厚的技术实力,成功研制出具有自主知识产权的瑞友天翼应用虚拟化系统(GWT System),瑞友天翼桌面虚拟化系统(RVD System),瑞友天翼服务器虚拟化系统(RVS System)全系列产品,曾获得两项政府专项资金支持,获得国家及软件行业内奖项数十项,服务着国内外四万多家企业,瑞友公司打造的集中、便捷、安全、高效的虚拟化支撑平台,降低用户信息化总体拥有成本(Total Cost of Ownership),极大提升信息化系统的使用价值。

3,246

社区成员

发帖
与我相关
我的任务
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
  • ATL/ActiveX/COM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧