• windows创建服务:更新服务信息乱码问题(ChangeServiceConfig)


            因为小项目需要创建windows服务,安装微软官方示例一切都挺顺利,代码运行后发现配置的信息在系统里显示乱码。打开注册表发现的确是乱码。这就排除软件读取得问题,而是调用ChangeServiceConfig系统函数写入时就发生了乱码。让我在网上查找了一下午,都没有结果。主要是我是按照官方的示例创建的呀,既然是官方示例,出现bug的可能就极小。没法,静下心来看官方文档吧。功夫不负有心人,终于让我发现了问题。记录一下错误过程:

            出现问题的地方是windows的很多函数都会用宏预先处理调用函数。因为历史的原因,很多函数都会有不同的变种,以自动适配函数和数据类型。比如:ChangeServiceConfig2A 和 ChangeServiceConfig2W 这两个函数,其功能是一样的。主要是数据类型发生了改变。SERVICE_DESCRIPTIONA,SERVICE_DESCRIPTIONW这两中数据类型服务于上面两种不同的函数。

            当我们调用ChangeServiceConfig2时,编译器会根据开发环境自动识别选用ChangeServiceConfig2A 或 ChangeServiceConfig2W。我出现问题的地方就是,编译器竟然给我混用了ChangeServiceConfig2A 函数,这个函数是为了兼容以前的老系统版本的,所使用的数据类型是LPSTR。我的开发环境是win11,使用的是LPWSTR数据类型。所以系统显示的配置信息是乱码。

    一、 我的开发环境是:windows11 + QT。这是我的开发环境。

    二、我按官方示例创建了服务,包括创建、卸载、停止、更新服务配置信息等等。在更新服务配置信息部分出现了写入乱码的问题,下面源码是修正过,运行正确的:

    1. //添加修改服务描述信息
    2. BOOL NpfConfig::SelfChangeServiceConfig(QString m_lpszDriverName, QString m_description)
    3. {
    4. SC_HANDLE schManager;
    5. SC_HANDLE schService;
    6. SERVICE_DESCRIPTIONW lpInfo;
    7. LPCWSTR lpszDriverName;
    8. LPWSTR description;
    9. std::wstring wLpszDriverName = m_lpszDriverName.toStdWString();
    10. lpszDriverName = wLpszDriverName.c_str();
    11. std::wstring wDescription = m_description.toStdWString();
    12. description = wDescription.data();
    13. lpInfo.lpDescription = description;
    14. qDebug()<
    15. schManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    16. if (NULL == schManager)
    17. {
    18. return FALSE;
    19. }
    20. schService = OpenService(schManager, lpszDriverName, SERVICE_ALL_ACCESS);
    21. if (NULL == schService)
    22. {
    23. CloseServiceHandle(schManager);
    24. return FALSE;
    25. }
    26. if (!ChangeServiceConfig2W(schService,
    27. SERVICE_CONFIG_DESCRIPTION,
    28. &lpInfo))
    29. {
    30. qDebug()<<"修改服务描述信息错误:"<<GetLastError();
    31. return false;
    32. }
    33. else
    34. {
    35. qDebug()<<"修改服务描述信息成功!";
    36. }
    37. CloseServiceHandle(schService);
    38. CloseServiceHandle(schManager);
    39. return true;
    40. }

    三、这是读取服务配置信息的函数。修正过,可以正常运行的。需要说明的是,上面的代码和下面的代码所用到的数据类型必须一致。我所出现的问题就是相信了编译器给我预处理的选择。最后我手动指定所用函数,而不是让编译器推荐的宏通用函数。

    1. //查询服务描述项
    2. BOOL NpfConfig::DoQueryDescription(QString m_serviceName)
    3. {
    4. DWORD dwBytesNeeded, cbBufSize=0, dwError;
    5. LPSERVICE_DESCRIPTIONW lpsd;
    6. LPWSTR serviceName;
    7. std::wstring wServiceName = m_serviceName.toStdWString();
    8. serviceName = wServiceName.data();
    9. // 打开服务控制管理器数据库
    10. SC_HANDLE schSCManager = OpenSCManager(
    11. NULL, // 目标计算机的名称,NULL:连接本地计算机上的服务控制管理器
    12. NULL, // 服务控制管理器数据库的名称,NULL:打开 SERVICES_ACTIVE_DATABASE 数据库
    13. SC_MANAGER_ALL_ACCESS // 所有权限
    14. );
    15. if (schSCManager == NULL) {
    16. CloseServiceHandle(schSCManager);
    17. qDebug()<<"服务开启时,服务管理器打开失败"<<GetLastError();
    18. return FALSE;
    19. }
    20. // 打开服务
    21. SC_HANDLE schService = OpenService(
    22. schSCManager, // 服务控件管理器数据库的句柄
    23. serviceName, // 要打开的服务名
    24. SERVICE_ALL_ACCESS // 服务访问权限:所有权限
    25. );
    26. if (schService == NULL) {
    27. CloseServiceHandle(schService);
    28. CloseServiceHandle(schSCManager);
    29. qDebug()<<"服务打开失败"<<GetLastError();
    30. return FALSE;
    31. }
    32. else
    33. {
    34. qDebug()<<"开启成功:开启服务返回得结果:"<
    35. }
    36. lpsd = (LPSERVICE_DESCRIPTIONW) LocalAlloc(LMEM_FIXED, cbBufSize);
    37. if( !QueryServiceConfig2(
    38. schService,
    39. SERVICE_CONFIG_DESCRIPTION,
    40. NULL,
    41. 0,
    42. &dwBytesNeeded))
    43. {
    44. dwError = GetLastError();
    45. if( ERROR_INSUFFICIENT_BUFFER == dwError )
    46. {
    47. cbBufSize = dwBytesNeeded;
    48. lpsd = (LPSERVICE_DESCRIPTIONW) LocalAlloc(LMEM_FIXED, dwBytesNeeded);
    49. }
    50. else
    51. {
    52. qDebug()<<"QueryServiceConfig2 failed:"<
    53. }
    54. }
    55. if (!QueryServiceConfig2(
    56. schService,
    57. SERVICE_CONFIG_DESCRIPTION,
    58. (LPBYTE) lpsd,
    59. cbBufSize,
    60. &dwBytesNeeded) )
    61. {
    62. qDebug()<<"QueryServiceConfig2 failed:"<<GetLastError();
    63. }
    64. else
    65. {
    66. qDebug()<<"QueryServiceConfig2 获取得描述信息:"<lpDescription;
    67. qDebug()<<"QueryServiceConfig2 获取得描述信息:"<fromStdWString(lpsd->lpDescription);
    68. }
    69. LocalFree(lpsd);
    70. CloseServiceHandle(schService);
    71. CloseServiceHandle(schSCManager);
    72. return true;
    73. }

  • 相关阅读:
    重装系统后原git项目报错
    linux安装jdk1.8并启动jar包(又一次配置环境,简单记录下,要是小白,刚接触,按照步骤来即可)
    Android 应用流量监控实践
    PHP基于thinkphp的网上书店管理系统#毕业设计
    从零到壹搭建一个商城架构--KubeSphere
    【自然语言处理】关系抽取 —— MPDD 讲解
    一零二零、C语言白菜入门--流程控制
    基于jeecg-boot的flowable流程历史记录显示修改
    M1通讯层的校验-尾块
    Day38——进程的创建方法,join方法,进程对象
  • 原文地址:https://blog.csdn.net/weixin_40583088/article/details/133781277