这边文章简单的向大家介绍一下如何用ATL 创建一个Service。
我用的是Visual studio 2010。
首先从VS2010中选择File -> New -> Project... 。选择Visual C++ -> ATL -> ATL Project。
写好Name,点击OK。再点击Next。然后选择Service(EXE),点击Finish。
这时你会发现一个空的Service就已经被创建了。然后里面只有两个函数。_tWinMain 和InitializeSecurity
明显只有这两个函数是不够的。因此还须添加其他一些函数。具体请看以下全部CPP内的代码。只需更改CPP内代码,就完成了。
// TestService.cpp : Implementation of WinMain
#include <stdio.h>
#include "stdafx.h"
#include "resource.h"
#include "TestService_i.h"
#define SERVICE_NAME _T("Test Service")
#define SERVICE_DESC _T("Test Service")
const TCHAR REG_KEY_TESTSRV[] = _T("SYSTEM\\CurrentControlSet\\Services\\Test Service");
class CTestServiceModule : public ATL::CAtlServiceModuleT< CTestServiceModule, IDS_SERVICENAME >
{
public :
DECLARE_LIBID(LIBID_TestServiceLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_TESTSERVICE, "{6F4B5E0D-EBCC-472C-AD6A-897DC5BA19A1}")
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.
HRESULT hResult = CoInitializeSecurity(
NULL,-1,NULL,NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,EOAC_NONE,NULL);
if(FAILED(hResult)){
return FALSE;
}
return S_OK;
}
HRESULT RegisterAppId(bool bService = false) throw()
{
if (!Uninstall()) {
return E_FAIL;
}
HRESULT hr = UpdateRegistryAppId(TRUE);
if (FAILED(hr)) {
return hr;
}
CRegKey keyAppID;
LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE);
if (lRes != ERROR_SUCCESS) {
return AtlHresultFromWin32(lRes);
}
CRegKey key;
lRes = key.Create(keyAppID, GetAppIdT());
if (lRes != ERROR_SUCCESS) {
return AtlHresultFromWin32(lRes);
}
key.DeleteValue(_T("LocalService"));
if (!bService)
return S_OK;
key.SetStringValue(_T("LocalService"), m_szServiceName);
// Create service
if (!Install()) {
return E_FAIL;
}
return S_OK;
}
BOOL Install() throw()
{
if (IsInstalled()) {
return TRUE;
}
// Get the executable file path
TCHAR szFilePath[MAX_PATH + _ATL_QUOTES_SPACE];
DWORD dwFLen = ::GetModuleFileName(NULL, szFilePath + 1, MAX_PATH);
if( dwFLen == 0 || dwFLen == MAX_PATH ) {
return FALSE;
}
// Quote the FilePath before calling CreateService
szFilePath[0] = _T('\"');
szFilePath[dwFLen + 1] = _T('\"');
szFilePath[dwFLen + 2] = 0;
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
return FALSE;
}
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("Winmgmt\0\0"), NULL, NULL);
if (hService == NULL)
{
::CloseServiceHandle(hSCM);
return FALSE;
}
//Service Settings
if(!UpdateServiceSetting(hService,szFilePath))
{
::CloseServiceHandle(hSCM);
return FALSE;
}
::CloseServiceHandle(hService);
::CloseServiceHandle(hSCM);
return TRUE;
}
int WinMain(HINSTANCE hInstance) throw()
{
HRESULT hr = S_OK;
LPTSTR lpCmdLine = GetCommandLine();
if (ParseCommandLine(lpCmdLine, &hr) == true) {
hr = Start(hInstance);
}
return hr;
}
HRESULT Start(HINSTANCE hInstance) throw()
{
CRegKey keyAppID;
LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_READ);
if (lRes != ERROR_SUCCESS)
{
m_status.dwWin32ExitCode = lRes;
return m_status.dwWin32ExitCode;
}
CRegKey key;
lRes = key.Open(keyAppID, GetAppIdT(), KEY_READ);
if (lRes != ERROR_SUCCESS)
{
m_status.dwWin32ExitCode = lRes;
return m_status.dwWin32ExitCode;
}
TCHAR szValue[MAX_PATH];
DWORD dwLen = MAX_PATH;
lRes = key.QueryStringValue(_T("LocalService"), szValue, &dwLen);
m_bService = FALSE;
if (lRes == ERROR_SUCCESS)
m_bService = TRUE;
if (m_bService)
{
SERVICE_TABLE_ENTRY st[] =
{
{ m_szServiceName, _ServiceMain },
{ NULL, NULL }
};
if (::StartServiceCtrlDispatcher(st) == 0)
m_status.dwWin32ExitCode = GetLastError();
return m_status.dwWin32ExitCode;
}
// local server - call Run() directly, rather than
// from ServiceMain()
m_status.dwWin32ExitCode = Run(hInstance);
return m_status.dwWin32ExitCode;
}
void ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv) throw()
{
lpszArgv;
dwArgc;
// Register the control request handler
m_status.dwCurrentState = SERVICE_START_PENDING;
m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
m_hServiceStatus = RegisterServiceCtrlHandler(m_szServiceName, _Handler);
if (m_hServiceStatus == NULL)
{
//LogEvent(_T("Handler not installed"));
return;
}
SetServiceStatus(SERVICE_START_PENDING);
m_status.dwWin32ExitCode = S_OK;
m_status.dwCheckPoint = 0;
m_status.dwWaitHint = 0;
#ifndef _ATL_NO_COM_SUPPORT
HRESULT hr = E_FAIL;
hr = InitializeCom();
if (FAILED(hr))
{
// Ignore RPC_E_CHANGED_MODE if CLR is loaded. Error is due to CLR initializing
// COM and InitializeCOM trying to initialize COM with different flags.
if (hr != RPC_E_CHANGED_MODE || GetModuleHandle(_T("Mscoree.dll")) == NULL)
{
return;
}
}
else
{
m_bComInitialized = true;
}
m_bDelayShutdown = false;
#endif //_ATL_NO_COM_SUPPORT
// When the Run function returns, the service has stopped.
m_status.dwWin32ExitCode = Run(SW_HIDE);
#ifndef _ATL_NO_COM_SUPPORT
if (m_bService && m_bComInitialized)
UninitializeCom();
#endif
SetServiceStatus(SERVICE_STOPPED);
//LogEvent(_T("Service stopped"));
}
HRESULT Run(HINSTANCE hInstance) throw()
{
HRESULT hr = S_OK;
hr = PreMessageLoop(SW_HIDE);
if (hr == S_OK)
{
if (m_bService)
{
//LogEvent(_T("Service started"));
SetServiceStatus(SERVICE_RUNNING);
}
RunMessageLoop(hInstance);
}
if (SUCCEEDED(hr))
{
hr = PostMessageLoop();
}
return hr;
}
HRESULT PreMessageLoop(int nShowCmd) throw()
{
HRESULT hr = __super::PreMessageLoop(SW_HIDE);
#if _ATL_VER >= 0x0700
if (SUCCEEDED(hr) && !m_bDelayShutdown)
hr = CoResumeClassObjects();
#endif
return hr;
}
void RunMessageLoop(HINSTANCE hInstance) throw()
{
MSG msg;
while (GetMessage(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
HRESULT PostMessageLoop()
{
return __super::PostMessageLoop();
}
void OnStop() throw()
{
SetServiceStatus(SERVICE_STOPPED);
__super::OnStop();
}
void OnShutdown() throw()
{
SetServiceStatus(SERVICE_STOPPED);
__super::OnShutdown();
}
BOOL UpdateServiceSetting(SC_HANDLE hService,LPCTSTR lpszFilePath)
{
if(!ChangeServiceConfig(
hService,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
lpszFilePath,
NULL,NULL,NULL,NULL,NULL,
SERVICE_NAME)){
return FALSE;
}
CRegKey keyTestService;
LONG lRes = keyTestService.Open(HKEY_LOCAL_MACHINE, REG_KEY_TESTSRV, KEY_WRITE);
if (lRes != ERROR_SUCCESS){
return FALSE;
}
keyTestService.SetStringValue(_T("Description"), SERVICE_DESC);
keyTestService.Close();
return TRUE;
}
};
CTestServiceModule _AtlModule;
//
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/, int /*nShowCmd*/)
{
return _AtlModule.WinMain(hInstance);
}