GetModuleFileName 的边缘情况不明确
Unclear edge-case of GetModuleFileName
MSDN docs 状态:
lpFilename [out]
A pointer to a buffer that receives the fully qualified path of the module. If the length of the path is less than the size that the nSize parameter specifies, the function succeeds and the path is returned as a null-terminated string.
If the length of the path exceeds the size that the nSize parameter specifies, the function succeeds and the string is truncated to nSize characters including the terminating null character.
Windows XP: The string is truncated to nSize characters and is not null-terminated.
这是模棱两可的。我是否将此解释为字符串在 Windows XP 上 never 以 null 结尾?或者它只是在字符串被截断时才没有以 null 终止?
如果有人知道一个措辞更好的参考,或者是 运行 Windows 某处的 XP 并且可以简单地测试行为,我将不胜感激。
我认为您需要在上面段落的上下文中阅读该行:
If the function succeeds, the return value is the length of the string that is copied to the buffer, in characters, not including the terminating null character. If the buffer is too small to hold the module name, the string is truncated to nSize characters including the terminating null character, the function returns nSize, and the function sets the last error to ERROR_INSUFFICIENT_BUFFER.
Windows XP: If the buffer is too small to hold the module name, the function returns nSize. The last error code remains ERROR_SUCCESS. If nSize is zero, the return value is zero and the last error code is ERROR_SUCCESS.
If the function fails, the return value is 0 (zero). To get extended error information, call GetLastError.
然后结合使用 return 值和对 GetLastError() 的调用来确定您是否拥有完整路径。
如果你有一个完整的路径 (ERROR_SUCCESS
) AND return-value == nSize
那么你不应该假设它是空终止的。
在我看来,这表明永远不要假设它以 null 结尾。接口坏了。您发送给函数的缓冲区应该比 nSize 大一个字符。然后你可以空终止。
从 c++11 开始,std::basic_string<TCHAR>
保证附加一个尾随零,所以像这样的事情应该做得很好:
std::basic_string<TCHAR> better_get_module_filename(HMODULE hModule)
{
std::basic_string<TCHAR> result(128, 0);
DWORD err = ERROR_SUCCESS;
do {
auto actual = GetModuleFileName(hModule, std::addressof(result[0]), result.size());
err = GetLastError();
if (actual == 0) {
throw "error of choice, wrapping err";
}
result.resize(actual);
} while(err == ERROR_INSUFFICIENT_BUFFER);
return result;
}
MSDN docs 状态:
lpFilename [out]
A pointer to a buffer that receives the fully qualified path of the module. If the length of the path is less than the size that the nSize parameter specifies, the function succeeds and the path is returned as a null-terminated string.
If the length of the path exceeds the size that the nSize parameter specifies, the function succeeds and the string is truncated to nSize characters including the terminating null character.
Windows XP: The string is truncated to nSize characters and is not null-terminated.
这是模棱两可的。我是否将此解释为字符串在 Windows XP 上 never 以 null 结尾?或者它只是在字符串被截断时才没有以 null 终止?
如果有人知道一个措辞更好的参考,或者是 运行 Windows 某处的 XP 并且可以简单地测试行为,我将不胜感激。
我认为您需要在上面段落的上下文中阅读该行:
If the function succeeds, the return value is the length of the string that is copied to the buffer, in characters, not including the terminating null character. If the buffer is too small to hold the module name, the string is truncated to nSize characters including the terminating null character, the function returns nSize, and the function sets the last error to ERROR_INSUFFICIENT_BUFFER.
Windows XP: If the buffer is too small to hold the module name, the function returns nSize. The last error code remains ERROR_SUCCESS. If nSize is zero, the return value is zero and the last error code is ERROR_SUCCESS.
If the function fails, the return value is 0 (zero). To get extended error information, call GetLastError.
然后结合使用 return 值和对 GetLastError() 的调用来确定您是否拥有完整路径。
如果你有一个完整的路径 (ERROR_SUCCESS
) AND return-value == nSize
那么你不应该假设它是空终止的。
在我看来,这表明永远不要假设它以 null 结尾。接口坏了。您发送给函数的缓冲区应该比 nSize 大一个字符。然后你可以空终止。
从 c++11 开始,std::basic_string<TCHAR>
保证附加一个尾随零,所以像这样的事情应该做得很好:
std::basic_string<TCHAR> better_get_module_filename(HMODULE hModule)
{
std::basic_string<TCHAR> result(128, 0);
DWORD err = ERROR_SUCCESS;
do {
auto actual = GetModuleFileName(hModule, std::addressof(result[0]), result.size());
err = GetLastError();
if (actual == 0) {
throw "error of choice, wrapping err";
}
result.resize(actual);
} while(err == ERROR_INSUFFICIENT_BUFFER);
return result;
}