问题
Given a WinAPI function which returns it's result via a C style string OUT parameter e.g.:
int WINAPI GetWindowTextW(
_In_ HWND hWnd,
_Out_ LPTSTR lpString,
_In_ int nMaxCount
);
Is there a better way of using the function than what I'm doing below?
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;
The above code works, but I have the following issues with it:
The buffer size is completely arbitrary since I have no way to know the length of the string that the function might return. This "feels" wrong to me - I have always tried to avoid magic numbers in my code.
If the function returns a string which is larger than the buffer, it will get truncated - this is bad!
Whenever the function returns a string which is smaller than the buffer, I will be wasting memory. This is not as bad as (2), but I'm not thrilled about the idea of setting aside large chunks of memory (e.g. 1024 bytes in my example above) for something that might only need a few bytes in practice.
Are there any other alternatives?
回答1:
Call the function multiple times with temporary buffers of different sizes. Begin with a buffer of, say, 8. Double the buffer size and call it again. Repeat until it returns the same count as the last time. Then you can allocate the exact size buffer and copy what you've got there. There are a number of Win32 functions with similar behavior.
You may use GetWindowTextLength()
, but it probably won't help much if there are race conditions (you may end up with a truncated text because of them).
回答2:
There are a few different patterns depending on which Windows API function you're using. With some, you can query first, sometimes by calling another function (e.g., GetWindowTextLengthW) but usually by passing NULL for the buffer. After you query, you allocate the size and call again to get the actual string data.
Even with query-allocate-query, you sometimes need to iterate as there could be a race condition. For example, consider what happens if the window title changes between the GetWindowTextLengthW and the GetWindowTextW calls.
You can also avoid an extra copy by using the string itself rather than a second buffer.
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;
}
While awkward, this isn't really a fault of the Windows API design. The API is designed to be a C interface, not C++. Since C is not object-oriented, it's pretty limited when it comes to handling strings. For C++ code, you can wrap this kind of bookkeeping as I've done in this example.
来源:https://stackoverflow.com/questions/14715848/working-with-winapi-functions-which-use-c-style-strings-as-out-parameters