必须用queryserviceconfig2并传service_config_description(值为1),先以null缓冲区调用获取所需字节数,再分配内存读取service_description结构,检查lpdescription非空后用widechartomultibyte转utf-8。

如何用 QueryServiceConfig2 获取服务描述
Windows 服务的描述信息(Display Name 之外的“说明”字段)不能靠 QueryServiceConfig 拿到,必须用 QueryServiceConfig2 并指定 SERVICE_CONFIG_DESCRIPTION 类型。这是最常踩的第一个坑:调用成功但返回空字符串,往往是因为传错了 dwInfoLevel。
- 必须先用
OpenSCManager获取 SCM 句柄,再用OpenService打开目标服务,且权限至少含QUERY_STATUS和QUERY_CONFIG -
QueryServiceConfig2第二个参数是dwordInfoLevel,描述信息对应的是SERVICE_CONFIG_DESCRIPTION(值为 1),不是 0 或其他常量 - 首次调用时传入
NULL缓冲区和 0 长度,函数会通过lpdwBytesNeeded返回所需字节数 —— 必须检查返回值是否为ERROR_INSUFFICIENT_BUFFER,否则直接分配固定大小容易溢出或截断
为什么 lpServiceDescription 总是空或乱码
拿到缓冲区后,要从返回结构中正确提取字符串。返回的是 SERVICE_DESCRIPTION 结构体,其 lpDescription 成员是指向内部宽字符字符串的指针,不是独立分配的内存。
- 不要直接
wprintf(L"%s", pDesc->lpDescription)—— 如果lpDescription为NULL(服务未设置描述),会崩溃;需先判空 - 该字符串是 UTF-16,若需转为 ANSI 或 UTF-8,必须用
WideCharToMultiByte,不能简单强转或 memcpy - 常见错误:把整个
SERVICE_DESCRIPTION结构体当字符串打印,结果看到乱码或地址值
完整调用链的关键顺序和错误检查点
漏掉任意一个失败路径检查,都会导致后续调用返回 ERROR_INVALID_HANDLE 或静默失败。
-
OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)失败 → 权限不足(需管理员)或服务控制管理器不可用 -
OpenService(hSCM, L"Winmgmt", SERVICE_QUERY_CONFIG)失败 → 服务名写错(注意是短名如Winmgmt,不是显示名 “Windows Management Instrumentation”)或服务不存在 -
QueryServiceConfig2返回 0 且GetLastError()是ERROR_ACCESS_DENIED→ 当前进程没被授予SE_SERVICE_QUERY_CONFIG_NAME权限,即使以管理员运行也不自动拥有,通常可忽略(描述非敏感信息,多数服务允许读)
示例片段:安全读取描述并转为 UTF-8
SC_HANDLE hSCM = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT);
if (!hSCM) return;
<p>SC_HANDLE hSvc = OpenService(hSCM, L"Winmgmt", SERVICE_QUERY_CONFIG);
if (!hSvc) {
CloseServiceHandle(hSCM);
return;
}</p><p>DWORD dwNeeded = 0;
if (!QueryServiceConfig2(hSvc, SERVICE_CONFIG_DESCRIPTION, nullptr, 0, &dwNeeded) &&
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
CloseServiceHandle(hSvc);
CloseServiceHandle(hSCM);
return;
}</p><p>auto* pDesc = static_cast<lpservice_description>(malloc(dwNeeded));
if (!pDesc) goto cleanup;</lpservice_description></p><p>if (QueryServiceConfig2(hSvc, SERVICE_CONFIG_DESCRIPTION, reinterpret_cast<lpbyte>(pDesc), dwNeeded, &dwNeeded)) {
if (pDesc->lpDescription) {
int len = WideCharToMultiByte(CP_UTF8, 0, pDesc->lpDescription, -1, nullptr, 0, nullptr, nullptr);
if (len > 0) {
std::string utf8_desc(len, '\0');
WideCharToMultiByte(CP_UTF8, 0, pDesc->lpDescription, -1, &utf8_desc[0], len, nullptr, nullptr);
// utf8_desc 现在包含可打印的描述文本
}
}
}</lpbyte></p><p>free(pDesc);
cleanup:
CloseServiceHandle(hSvc);
CloseServiceHandle(hSCM);</p>
真正容易被忽略的是:服务描述可能根本没设置,lpDescription 就是 NULL;还有 WideCharToMultiByte 的返回值必须检查,否则 UTF-8 转换失败时你会拿到空字符串却以为服务没描述。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











