开发环境 vs 2010 (但方法适用于VS2005 及 VS 2008)c++ atl 版
在编译出exe以后使用release下的批处理安装卸载服务
在windows里的服务控制面板进行服务的启动和停止操作
本程序是完整的windows 服务开发框架,直接在里面添加业务代码就可以
产生一个标准的服务程序
带有一个日志文件
http://b.qjwm.com/down.aspx?down=ok&filepath=dante300%2fwindows+service%2fwindow+service.rar
知识性说明
原文出处:http://topic.csdn.net/u/20070126/09/c1d1279a-bbac-45b9-8e88-835b8956d97e.html
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);
}