服务在Window中越来越普及,它有一些不错的优点:自启动、被杀进程后强制自启、在Vista下自动拥有最高权限等。
下面介绍服务的用法。
其实编程上服务和一般的EXE几乎没差别,由一个Exe很容易可以改成服务的形式。步骤如下:
1、改写main函数,下面代码直接使用了服务的框架类,因为服务机制高度统一,所以相关机制直接由框架类来实现,框架类在后面解说。
下面是Main函数:
int _tmain(int argc, _TCHAR* argv[])
{
CServiceImpl *pServiceImpl = new CServiceImpl;
_Module.SetImpl(pServiceImpl);
if (argc < 2)
{
_Module.Start(argc, argv);
return 0;
}
// 安装&&反安装
if (_tcscmp(argv[1], _T("-install")) == 0)
{
_Module.Install();
}
else if (_tcscmp(argv[1], _T("-uninstall")) == 0)
{
_Module.Uninstall();
}
return 0;
}
服务由两种调用方式,一是由服务管理器调用(就是“控制面板”->“管理工具”->“服务”),二是直接调用,所以一边会在直接调用中加上安装和反安装处理。上面代码已经做了这个处理。
安装代码:
BOOL XServiceModule::Install()
{
if (IsInstalled())
return TRUE;
if ( m_pImpl )
{
if ( !m_pImpl->Install() )
{
cerr << "Install service -- Failed" << endl;
return FALSE;
}
}
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
cerr << "Install service -- Couldn't open service manager" << endl;
return FALSE;
}
// Get the executable file path
TCHAR szFilePath[_MAX_PATH];
::GetModuleFileName(NULL, szFilePath, _MAX_PATH);
SC_HANDLE hService = ::CreateService(
hSCM, GetName(), GetDisplayName(),
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
m_pImpl->IsAutoStart() ? SERVICE_AUTO_START : SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
szFilePath, NULL, NULL,
m_pImpl->GetDependencies(), NULL, NULL);
if (hService == NULL)
{
::CloseServiceHandle(hSCM);
cerr << "Install service -- Couldn't create service" << endl;
return FALSE;
}
::CloseServiceHandle(hService);
::CloseServiceHandle(hSCM);
cerr << "Install service -- OK" << endl;
return TRUE;
}
可见,调用CreateService向SCManager(服务管理器)注册进去即可。注意CreateService中的参数,服务对应的一些设置由此函数指定,如SERVICE_INTERACTIVE_PROCESS(允许与桌面交互)等。具体可看MSDN或服务管理器中的一些设置。
反安装:
BOOL XServiceModule::Uninstall()
{
if (!IsInstalled())
return TRUE;
if ( m_pImpl )
{
if ( !m_pImpl->Uninstall() )
{
cerr << "Uninstall service -- Failed" << endl;
return FALSE;
}
}
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
cerr << "Uninstall service -- Couldn't open service manager" << endl;
return FALSE;
}
SC_HANDLE hService = ::OpenService(hSCM, GetName(), SERVICE_STOP | DELETE);
if (hService == NULL)
{
::CloseServiceHandle(hSCM);
cerr << "Uninstall service -- Couldn't open service" << endl;
return FALSE;
}
SERVICE_STATUS status;
::ControlService(hService, SERVICE_CONTROL_STOP, &status);
BOOL bDelete = ::DeleteService(hService);
::CloseServiceHandle(hService);
::CloseServiceHandle(hSCM);
if (bDelete)
{
cerr << "Uninstall service -- OK" << endl;
return TRUE;
}
cerr << "Uninstall service -- Service could not be deleted" << endl;
return FALSE;
}
重点关注的是服务的入口函数:
void XServiceModule::Start(int argc, TCHAR **argv)
{
static
SERVICE_TABLE_ENTRY st[] =
{
{ (LPTSTR)GetName(), ServiceMain },
{ NULL, NULL }
};
if ( !(::StartServiceCtrlDispatcher(st)) )
{
//Error
}
}
上面代码指定了服务入口函数为 ServiceMain,下面来看一下此函数:
void XServiceModule::ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
{
_Module.m_bService = TRUE;
// Register the control request handler
m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
m_status.dwWin32ExitCode = 0;
m_status.dwServiceSpecificExitCode = 0;
m_status.dwCheckPoint = 0;
m_status.dwWaitHint = 0;
m_status.dwCurrentState = SERVICE_START_PENDING;
m_hServiceStatus = RegisterServiceCtrlHandler(GetName(), _Handler);
if (m_hServiceStatus == NULL)
{
LogEvent(EVENTLOG_ERROR_TYPE, TEXT("Handler not installed"));
return;
}
SetServiceStatus(SERVICE_START_PENDING);
m_status.dwWin32ExitCode = S_OK;
m_status.dwCheckPoint = 0;
m_status.dwWaitHint = 0;
// When the Run function returns, the service has stopped.
Run(dwArgc, lpszArgv);
SetServiceStatus(SERVICE_STOPPED);
}
此函数首先要向服务管理器注册ServiceHandle,此Handle是由服务管理器调用的(它自己另辟线程),注意注册前设置的State的参数,这些参数也直接对应服务的一些设置,如SERVICE_ACCEPT_STOP表示允许在服务管理器中显示“Stop”按钮,用户可以通过此按钮关掉服务。若不允许,则用户看到的“Stop”按钮是灰掉的。
仓促记下,有空再整理~