ATL框架下编写Windows服务

前段时间有个开发一个Windows服务的需求,且不能使用.NET, 之后在对比了Win32 和 ATL两种编写Windows服务的途径, 还是选择了后者.

Mark几个地方

  • 重载InitializeSecurity()函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    HRESULT InitializeSecurity() throw()
    {
    // TODO : 调用 CoInitializeSecurity 并为服务提供适当的
    // 安全设置
    // 建议 - PKT 级别的身份验证、
    // RPC_C_IMP_LEVEL_IDENTIFY 的模拟级别
    // 以及适当的非 NULL 安全说明符。
    return CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
    RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL );
    }
  • 重载RegisterAppId函数,注册服务的相关信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    HRESULT CXXXXXServiceModule::RegisterAppId(bool bService = false) throw()
    {
    HRESULT hr = S_OK;
    BOOL res = __super::RegisterAppId(bService);
    if (bService)
    {
    if (IsInstalled())
    {
    SC_HANDLE hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    SC_HANDLE hService = NULL;
    if (hSCM == NULL)
    hr = AtlHresultFromLastError();
    else
    {
    hService = ::OpenService(hSCM, m_szServiceName, SERVICE_ALL_ACCESS);
    if (hService != NULL)
    {
    ::ChangeServiceConfig(hService, SERVICE_NO_CHANGE, SERVICE_AUTO_START, // 服务自启动
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, m_szServiceName); // 通过修改资源IDS_SERVICENAME 修改服务的显示名字
    SERVICE_DESCRIPTION Description;
    TCHAR szDescription[1024];
    ZeroMemory(szDescription, 1024);
    ZeroMemory(&Description, sizeof(SERVICE_DESCRIPTION));
    lstrcpy(szDescription, _T("这里添加服务的描述内容"));
    Description.lpDescription = szDescription;
    ::ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &Description);
    ::CloseServiceHandle(hService);
    }
    else
    hr = AtlHresultFromLastError();
    ::CloseServiceHandle(hSCM);
    }
    }
    }
    return hr;
    }
  • 重载run( )函数, 网上有的说重载PreMessageLoop( )函数添加自定义代码,其实看atl头文件, 重载run比较”正宗”.

    1
    2
    3
    4
    5
    HRESULT CXXXXXServiceModule::Run(int nShowCmd) throw()
    {
    // 添加服务启动的自定义代码
    return __super::Run(nShowCmd);
    }
  • 重载stop( )函数, 添加服务停止的相关代码.

    1
    2
    3
    4
    5
    void CXXXXXServiceModule::OnStop() throw()
    {
        // 释放所有资源
        __super::OnStop();
    }

以上这些函数都不能抛出异常,这点很重要, 最好都用try{ } catch(){}块捕获, 如果有异常的话服务的操作就会失败造成服务的无响应.同时为了不让服务的启动和停止超时, 最好开启别的线程去完成任务.

注册服务: MyService.exe /Service
卸载服务: MyService.exe /UnRegServer

调试/测试服务的时候难免会导致服务进程的崩溃, 服务列表上无法操作, 这时候检查下面几点去清除/卸载服务:

  1. 如果有安装程序, 在添加/删除程序里卸载服务的程序, 前提条件是服务有响应, 并且卸载服务的命令不能有异常和失败;
  2. 在注册表路径[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services]中找到自己的服务,删除;
  3. 在注册表里搜索自己的服务名, 删除所有的键值;
  4. 任务管理器里结束服务进程.