在VC++6与VC++.Net 2003中使用ATL开发Windows服务时,是有一些区别的。
其原因是VC++6与VC++.Net 2003中ATL的版本不同。
VC++.Net 2003中,ATL的版本为7.0,用于处理Windows服务的部分已被封装。
在VC++.Net 2003中使用ATL开发Windows服务的基本步骤如下:
1、创建ATL工程。在ATL工程向导中,选择“Application Setting”,
服务器类型(Server type)选择“Service(EXE)”,其中,“Attributed”我通常是不选的。
工程创建完毕后,ATL工程向导将自动生成两个工程,“xxxx”和“xxxxPS”, 如:Test, TestPS。
通常我是删掉“xxxxPS”这个工程。
2、在ATL工程向导自动创建的类CxxxxModule中,重载CAtlServiceModuleT的两个方法:
PreMessageLoop、PostMessageLoop
其中,PreMessageLoop用于Windows服务启动前的初始化工作,并创建一个工作线程,以完成具体的处理。
(启动服务将调用PreMessageLoop方法)。注意:重载PreMessageLoop方法时,必须返回S_OK。
PostMessageLoop用于Windows服务停止后释放某些相关资源,并终止工作线程的运行。
(停止服务时将调用PostMessageLoop方法)。
3、如果要对命令行参数进行处理,则重载ParseCommandLine方法。
下面是一个Windows服务的代码片段:
class CTestModule : public CAtlServiceModuleT< CTestModule, IDS_SERVICENAME >
{
public :
DECLARE_LIBID(LIBID_TestLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_Test, "{CE42CD12-B8BD-44F3-9BC6-56CA0790E71B}")
HRESULT InitializeSecurity() throw()
{
// TODO : Call CoInitializeSecurity and provide the appropriate security settings for
// your service
// Suggested - PKT Level Authentication,
// Impersonation Level of RPC_C_IMP_LEVEL_IDENTIFY
// and an appropiate Non NULL Security Descriptor.
return S_OK;
}
//
// 在ATL 7.0中,用于处理Windows服务的部分已被封装。
//
// 通过重载PreMessageLoop与PostMessageLoop方法来初始化或释放
// Windows服务的相关资源。
//
HRESULT PreMessageLoop(int nShowCmd) throw()
{
HRESULT hr = S_OK;
//
// 启动服务的工作线程
//
hr=CAtlServiceModuleT<CTestModule,IDS_SERVICENAME>::PreMessageLoop(nShowCmd);
memset(m_szServer,0,_MAX_PATH);
m_dwPort=0;
if(!m_Listener.Create(m_szServer,m_dwPort))
{
PrintMessage(_T("绑定网络地址%s:%d失败,请检查网络配置,服务终止。"),
m_szServer, m_dwPort );
return E_FAIL;
}
//
// 启动Socket监听线程
//
if(!m_Listener.Run())
{
PrintMessage( _T("异常!服务线程启动失败,服务终止。") );
return E_FAIL;
}
return S_OK;
}
HRESULT PostMessageLoop() throw()
{
HRESULT hr = S_OK;
hr=CAtlServiceModuleT<CTestModule,IDS_SERVICENAME>::PostMessageLoop();
//
// 终止Socket监听线程
//
m_Listener.Shutdown();
return hr;
}
bool ParseCommandLine(LPCTSTR lpCmdLine,HRESULT* pnRetCode) throw()
{
bool bResult;
bResult = CAtlServiceModuleT<CTestModule,IDS_SERVICENAME>::ParseCommandLine(lpCmdLine, pnRetCode);
if(!bResult)
{
TCHAR szTokens[] = _T("-/");
LPCTSTR lpszToken= FindOneOf(lpCmdLine,szTokens);
while (lpszToken != NULL)
{
if (WordCmpI(lpszToken, _T("Service"))==0)
{
SetupRegistry();
break;
}
lpszToken = FindOneOf(lpszToken, szTokens);
}
}
return bResult;
}
private:
CListener m_Listener;
char m_szServer[_MAX_PATH];
DWORD m_dwPort;
};