如何将变长字符串从RPC服务器传递给客户端?

5
我正在实现一个Windows系统服务,它充当RPC服务器和对应的C++客户端。我正在使用纯Windows RPC功能。
从RPC客户端向服务器传递字符串很容易。只需在IDL文件中声明函数参数即可:
[in, string] wchar_t* myString

MIDL会处理内存分配的魔法。非常好用。

返回修改后的客户端字符串也很容易:

[in, out, string] wchar_t* myString

这需要我在客户端上正确地调整字符串大小。

问题:

我需要从服务器返回字符串到客户端。我不知道客户端的大小,所以在客户端进行内存分配不是一个选项。

可以分配非常大的内存,比如10K,足够大到可以容纳服务器可能返回的每个字符串。但这是一种巨大的资源浪费(内存、网络),而且我仍然不能确定服务器是否需要返回更大的字符串。

我尝试过的方法:

除了其他尝试之外,我尝试了 Microsoft 的 strout 示例中使用的技术。它可以在第一次调用 RPC 函数时工作,但在第二次调用时会导致服务器崩溃。

1个回答

8

MSDN页面多级指针让我找到了正确的方法。通过其中给出的示例和解释,我成功地使其工作。关键部分如下:

IDL文件:

error_status_t ReturnsString
(
   [out]                   long*     size,
   [out, size_is(, *size)] wchar_t** outString
);

服务器功能:

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;
}

我不知道为什么乘以二(stringSize * 2)是必要的,但确实如此。如果省略,会立即导致堆破坏。
客户端代码:
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);

3
您正在使用Unicode字符串,每个字符占用2个字节,因此您需要将字符串长度乘以sizeof(wchar)... - Remko
@Remko 是的,没错,但我指的是下一行,我猜想是:midl_user_allocate (stringSize * 2)。 - Helge Klein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接