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

Ran*_*dom 2 c# c++ com com-interop marshalling

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

C#

public string GetValue([MarshalAs(UnmanagedType.LPWStr)] string key)
{
   return "value";
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

BSTR result;
obj->GetValue(key, &result);
SysFreeString(key);
SysFreeString(result);
Run Code Online (Sandbox Code Playgroud)

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

Han*_*ant 7

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

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


Ant*_*hyy 5

要将属性应用于返回值:

[return: MarshalAs(UnmanagedType.LPWStr)]
public string GetValue([MarshalAs(UnmanagedType.LPWStr)] string key)
{
   return "value";
}
Run Code Online (Sandbox Code Playgroud)

您需要使用(我认为)手动释放字符串CoTaskMemFree

LPWSTR result ;
if (SUCCEEDED (obj->GetValue (key, &result)))
{
    // use result and free it when no longer needed
    CoTaskMemFree (result) ;
}
Run Code Online (Sandbox Code Playgroud)