【问题标题】:WCHAR array not properly marshalledWCHAR 数组未正确编组
【发布时间】:2009-05-13 11:47:06
【问题描述】:

我有一个带有以下方法定义(IDL 表示法)的 COM 接口:

SCODE GetText( [in, out] ULONG* pcwcBuffer,
              [out, size_is(*pcwcBuffer)] WCHAR* awcBuffer );

Typelib封送用于COM+,类型库已注册,接口的其他方法通过COM+调用时可以正常工作,但不是这个方法。

服务器端将 WCHAR 数组复制到 awcBuffer 并将其长度复制到 pwcBuffer,不会发生缓冲区溢出。

static const wchar_t* Text = L"Sample";
STDMETHODIMP CImpl::GetText( ULONG* bufferLength, WCHAR* buffer )
{
    const int length = wcslen( Text );
    *bufferLength = length;
    memcpy( buffer, Text, length * sizeof( WCHAR ) );
    return S_OK;
}

当客户端通过 COM+ 调用此方法时,缓冲区内容会丢失。具体来说,仅保留第一个宽字符 - 如果服务器复制“Sample”宽字符串,则客户端仅接收“S”字符串。客户端大小的返回值为S_OK,返回给客户端的缓冲区长度与服务器复制的完全相同。

我终于改用 BSTR 来解决这个问题,但有趣的是为什么整个看起来有效的构造不起作用。

所描述行为的可能原因是什么?

【问题讨论】:

    标签: windows com interop marshalling


    【解决方案1】:

    IIRC,typelib 编组器忽略 size_is 属性——因此,只有 1 个字符被编组。

    【讨论】:

      【解决方案2】:

      J。路过是对的。要使 typelib 编组器工作,COM 接口必须与 OLE 自动化兼容。 typelib marshaller是在oleaut32.dll中实现的,所以我猜名字里有线索。

      [size_is] 是完全有效的 IDL,并编译成有效的类型库,但类型库编组器只能处理有效接口的子集。该子集通常称为 OLE 自动化。顺便说一句,VB6 客户端只能说 OLE 自动化,因此他们也无法使用您的界面。

      尝试使用 IDL 中的 [oleautomation] 属性标记您的接口。它应该会给您一个警告或错误消息,可能会指向您关于该主题的更多信息。

      在“普通”COM 中,您可以从 IDL 生成代理/存根 DLL 来进行编组,但恐怕我不记得 COM+ 是否会使用您的自定义编组代码,即使您费心构建它.

      更新:在 Juval Lowy 的“COM 和 .NET 组件服务”一书中,我发现了这样的说法:“...配置的组件不能使用需要自定义编组的接口”。所以我猜这个接口永远不会在 COM+ 中工作。如果可以,请重新编写以使用 BSTR。

      【讨论】:

      • 该接口同时具有“dual”和“oleautomation”属性,但 MIDL 不会发出任何警告。
      • 你是对的。我也试过了,没有提示。对不起,对 MIDL 有太多的信心 ;-) 我仍然相信通用编组器无法做到 [size_is]。
      • 关于引用:虽然自定义封送处理确实不能用于 COM+,但您当然可以使用从 IDL 为 COM+ 生成的代理/存根 DLL。顺便说一下,这是一个常见的误解。
      【解决方案3】:

      几个问题:

      • 你为什么不使用BSTR
      • 你有GetText函数的来源吗?
      • 函数返回的缓冲区大小是多少?

      【讨论】:

      • 现在我正在使用 BSTR,但有趣的是为什么原始版本不起作用。更新了问题以澄清您提出的所有问题。
      猜你喜欢
      • 1970-01-01
      • 2013-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多