使用使用C风格字符串作为OUT参数的WinAPI函数
Working with WinAPI functions which use C style strings as OUT parameters
给定一个WinAPI函数,该函数通过C风格的字符串OUT参数返回其结果,例如:
int WINAPI GetWindowTextW(
_In_ HWND hWnd,
_Out_ LPTSTR lpString,
_In_ int nMaxCount
);
有没有比我下面所做的更好的方法来使用这个函数?
HWND handle; // Assume this is initialised to contain a real window handle
std::wstring title;
wchar_t buffer[512];
GetWindowTextW(handle, buffer, sizeof(buffer));
title = buffer;
上面的代码有效,但我有以下问题:
缓冲区大小完全是任意的,因为我无法知道函数可能返回的字符串的长度。这种"感觉"对我来说是错误的——我一直试图在代码中避免使用幻数。
如果函数返回的字符串大于缓冲区,它将被截断——这很糟糕!
每当函数返回一个小于缓冲区的字符串时,我就会浪费内存。这并没有(2)那么糟糕,但我对留出大块内存(例如,在上面的例子中为1024字节)用于实践中可能只需要几个字节的东西的想法并不感到兴奋。
还有其他选择吗?
使用不同大小的临时缓冲区多次调用函数。从缓冲区开始,比如说8。将缓冲区大小增加一倍,然后再次调用。重复,直到返回与上次相同的计数。然后,您可以分配确切大小的缓冲区,并复制您在那里得到的内容。有许多Win32函数具有类似的行为。
您可以使用GetWindowTextLength()
,但如果存在竞争条件(可能会因此而导致文本被截断),它可能不会有多大帮助。
根据您使用的Windows API函数,有几种不同的模式。对于某些函数,您可以先进行查询,有时通过调用另一个函数(例如GetWindowTextLengthW),但通常通过为缓冲区传递NULL。查询后,分配大小并再次调用以获取实际的字符串数据。
即使使用查询分配查询,有时也需要迭代,因为可能存在竞争条件。例如,考虑如果窗口标题在GetWindowTextLengthW和GetWindowTextW调用之间发生更改会发生什么。
您还可以通过使用字符串本身而不是第二个缓冲区来避免额外的副本。
std::wstring GetWindowTitle(HWND hwnd) {
std::wstring title(16, L'X');
int cch;
do {
title.resize(2 * title.size());
cch = GetWindowTextW(hwnd, &title[0], title.size());
} while (cch + 1 == title.size());
title.resize(cch);
return title;
}
虽然很尴尬,但这并不是Windows API设计的错。API被设计成一个C接口,而不是C++。由于C不是面向对象的,所以它在处理字符串方面非常有限。对于C++代码,您可以像我在本例中所做的那样包装这种记账。
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 指向具有 2 个参数的 WINAPI 函数的 Typedef 指针
- 如何初始化 WinApi ldap_search_s的 PZPWSTR (wchar_t**) 参数?
- WinAPI 混淆了函数参数
- 从命令行到纯 winapi 中的 MessageBox 的参数(C++没有标准库)
- Winapi:在类成员功能上创建新线程 - 不兼容的参数类型
- 是否有一个WinAPI可以从带有可选空格和其他参数的命令行获取文件名
- winapi GetProcessMemoryInfo 无效参数问题
- 与具有字符串输出参数的 WinAPI 函数的一致性是多少
- 使用使用C风格字符串作为OUT参数的WinAPI函数