如何将函数返回值编组到非托管dll

时间:2012-11-08 22:39:23

标签: c# c++ com marshalling com-interop

我有一个用C#编写的dll,并且暴露给COM。我在构建器中使用dll ...我可以实例化该类,但是在编译C#方法调用的返回值方面存在问题。

C#

public string GetValue([MarshalAs(UnmanagedType.LPWStr)] string key)
{
   return "value";
}

导入到构建器中的已翻译函数:

virtual HRESULT STDMETHODCALLTYPE GetValue(LPWSTR key/*[in]*/, 
                                           BSTR* pRetVal/*[out,retval]*/) = 0;

我对C ++知之甚少。 'key'参数传递得很好,因为我能够在参数上使用'MarshalAs'属性,但我要么不知道如何为返回值声明它,要么不知道如何调用在C ++方面的功能(我尝试了几件事,只是猜测)。

更新:好的,我只是通过采取Anton的例子并根据Hans的评论尝试修改来解决问题。 Antons的回答正如他所展示的那样,但是由于对内存管理问题的关注,我最终没有在C#中应用return属性,而C ++代码调用函数如下:

BSTR result;
obj->GetValue(key, &result);
SysFreeString(key);
SysFreeString(result);

我希望我能帮助我解决这两个问题的答案,他们都必须向我提供我需要的信息。

1 个答案:

答案 0 :(得分:7)

您可以应用[return:]属性,但这是一个非常糟糕的主意。此函数签名的问题是被调用者必须为字符串分配缓冲区,并且调用者必须释放它。这需要两者都使用相同的堆。当强制它使用LPWSTR时,就是这种情况,CLR使用自己的堆而你无法从本机代码中获取它,你无法获得所需的堆处理。

两段代码必须使用相同的堆。并且有一个特别为此目的,COM堆。 BSTR是一个使用该堆的字符串类型,CLR会自动使用它,就像您从签名中看到的那样。要使用它,只需在调用后访问pRetVal指针,它就是一个wchar_t *。然后你必须释放它,调用SysFreeString()。