下面是一个示例代码(只有示例代码才能轻松理解,没有错误处理,没有关闭句柄等等):
SC_HANDLE hSCManager = ::OpenSCManager(nullptr, nullptr, 0);
DWORD buffSize = 0;
::GetServiceDisplayName(hSCManager, m_serviceName, nullptr, &buffSize);
LPTSTR buff = new TCHAR[++buffSize];
VERIFY(::GetServiceDisplayName(hSCManager, m_serviceName, buff, &buffSize));
我的示例服务的显示名称为"notepad starter"
(15个字符)。
在构建配置之间切换,GetServiceDisplayName()
在ANSI(GetServiceDisplayNameA
)下返回缓冲区大小30,在UNICODE(GetServiceDisplayNameW
)下返回15。
此API的文档说它返回字符中的缓冲区大小,不包括空终止符(没有详细记录,但我希望缓冲区大小在第二次调用中包含空终止符)。
为什么它在不同的构建配置中返回不同的缓冲区大小?
答案 0 :(得分:3)
首先GetServiceDisplayName
将服务控制管理器数据库( hSCManager )作为第一个参数处理,但不处理服务( hService ) - 所以你不需要为此任务提供开放服务。你不需要SC_MANAGER_ALL_ACCESS
,但0就够了。
然而你的主要错误在下一个。你在字符中分配缓冲区new TCHAR[buffSize + 1]
- 所以buffSize + 1
- 这是正确的,因为GetServiceDisplayName
返回服务显示名称的大小,不包括空终止字符 - 所以我们需要额外的一个字符空间来终止0;
但是在下一行错误 - &buffSize
- 最后一个参数 lpcchBuffer 必须包含缓冲区的大小(以字符为单位)。所以你分配的确切缓冲区大小。但是您分配buffSize + 1
空格,而不是buffSize
。所以代码必须是下一个:
if (SC_HANDLE hSCManager = OpenSCManagerW(nullptr, nullptr, 0))
{
DWORD cch = 0;
if (!GetServiceDisplayNameW(hSCManager, m_serviceName, nullptr, &cch))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
PWSTR buff =(PWSTR)alloca(++cch*sizeof(WCHAR));
if (GetServiceDisplayNameW(hSCManager, m_serviceName, buff, &cch))
{
DbgPrint("%S\n", buff);
}
}
}
CloseServiceHandle(hSCManager);
}
因此,您的代码必须将buffSize + 1
替换为++buffSize
关于ansi版本 - GetServiceDisplayNameA
- 这里api实现真的很错误 - 如果字符中的缓冲区大小不够大 - 它会返回多少字节需要 unicode 服务名称,不包括空终止符号。如果缓冲区足够大,它根本不会更新 lpcchBuffer 。这还有一个参数从不使用api的A
版本,但总是W