I am implementing a Windows system service, which acts as RPC server, and a corresponding client, both in C++. I am using plain Windows RPC functionality.
Passing strings from the RPC client to the server is easy. Just declare the function parameter in the IDL file like this:
[in, string] wchar_t* myString
MIDL will take care of the memory-allocation magic. Works like a treat.
Returning a modified client string is also easy:
[in, out, string] wchar_t* myString
That requires me to properly size the string on the client side, though.
Problem:
I need to return strings from the server to the client. I do not know on the client how large they are going to be, so memory allocation on the client is not an option.
I could allocate a very large amount of memory, say 10K, an amount large enough for every string the server could possibly return. But that is a huge waste of resources (memory, network), and I still cannot know for certain that the server never needs to return a larger string.
What I tried:
Amonst many other things I tried the technique used in Microsoft's strout sample. It worked when calling the RPC function for the first time, but crashed the server when called for the second time.
The MSDN page Multiple Levels of Pointers brought me on the right track. With the example and explanation given there I managed to make it work. The essentail parts are as follows:
IDL file:
error_status_t ReturnsString
(
[out] long* size,
[out, size_is(, *size)] wchar_t** outString
);
Server function:
error_status_t ReturnsString (long* size, wchar_t** outString)
{
wstring outStringWString = L"Return this to caller";
int stringSize = sizeof(wchar_t) * (outStringWString.size() + 1);
*outString = (wchar_t*) midl_user_allocate (stringSize * 2);
wcscpy_s (*outString, stringSize, outStringWString.c_str());
*size = outStringWString.size() + 1;
return ERROR_SUCCESS;
}
I do not know why the multiplication by two (stringSize * 2) is necessary, but it is. If omitted, you get instant heap corruption.
Client code:
wchar_t** versionRPC = (wchar_t**) midl_user_allocate (sizeof(wchar_t*));
*versionRPC = NULL; // Required to create a unique pointer
long stringSize = 0;
DWORD retVal = ReturnsString (&stringSize, versionRPC);
// Copy the returned string
wstring stringFromServer (*rpcString);
MIDL_user_free (*rpcString);
MIDL_user_free (rpcString);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With