从 C++ COM 转换为 C# 的字符串

3

我有一个C++ DLL,一些函数返回Unicode空终止字符串:

void SomeFunc(wchar_t* StrBuf)

调用者必须分配StrBuf - 字符串最长可达256个字符。 此DLL还通过COM公开了一个COM对象,以便从C#中使用此DLL。在IDL中定义如下:

[id(1), helpstring("bla")]
HRESULT SomeFunc([in,out] BSTR* TextStr, [out,retval] LONG* RetValue);

目前C#代码如下:

string val = new string('\0', 256); // Allocate memory
MyComObj.SomeFunc(ref val); // Get string
val = val.Substring(0, val.IndexOf('\0')); // Convert from null-terminated string

有没有办法定义这样一个COM函数,使得它更容易从C#中调用?现在看起来很丑,并且需要三行代码才能调用该函数,如果函数有两个字符串参数,则需要五行代码。

请查看com interop http://msdn.microsoft.com/en-us/library/aa645736(v=vs.71).aspx - parapura rajkumar
此函数存在严重问题,违反了自动化契约。您的代码正在改变字符串,但在 .NET 中字符串是不可变的。虽然它可以偶尔运行,但会有足够的空间破坏托管堆的完整性。 您必须修复该函数。 - Hans Passant
好的,这个解决方案不太好,但是你没有提出更好的方法。 "com interop" 文章并不实用,它们没有描述如何处理字符串。 - Mike
最终我找到了如何从C++ COM返回字符串到C#的方法:https://dev59.com/aUjSa4cB1Zd3GeqPJ_aX - Mike
如果您有解决方案,请创建并回答自己的问题,并将其标记为答案,以便关闭。 - Simon Mourier
3个回答

0
如果客户端为字符串分配内存并将其填充到COM服务器中,则必须使用StringBuilder:
// IDL code
HRESULT GetStr(/*[out]*/ LPSTR pStr);

// Interop
void GetStr(/*[out]*/ [MarshalAs(UnmanagedType.LPStr)] StringBuilder pStr);

// C# code
var str = new StringBuilder(256);
MyComObj.GetStr(a);

然后StringBuilder将为空或填充有字符。


0

问题已解决。在C++中,我在COM包装器中使用了这段代码:

STDMETHODIMP MyClassClass::SomeFunc(BSTR* OptionValue, LONG* RetValue)
{
    *RetValue = 0;
    UNICODECHAR txt[MAXSTATSTRLEN];

    //... Copy text to txt variable
    *OptionValue = W2BSTR(txt);
    return S_OK;
}

IDL:

[id(1), helpstring("")] HRESULT SomeFunc([out] BSTR* OptionValue, [out,retval] LONG* RetValue);

在C#中现在可以轻松地调用:

string val;
MyComObj.SomeFunc(out val);

0
如果您将其公开为COM对象,只需使用Visual Studio向您的对象添加引用即可。它会自动生成一个程序集(我相信他们称之为COM可调用包装器)。
这将使您的COM对象方法暴露给.NET,并且可以正常工作,除非您开始尝试传递一些自定义结构。
以下是一些资源供您参考: COM可调用包装器 COM互操作性第1部分:C#客户端教程

1
COM Callable Wrapper是一个运行时实体,用作COM端的代理,当托管端充当服务器时。对于OP的情况(.NET是客户端),此代理对象称为Runtime Callable Wrapper,但这对于托管调用者来说大多数情况下并不重要。虽然VS帮助创建这些托管签名,但仍然是调用者的责任在必要时通过进行分配和释放来防止内存泄漏。而且对于[In,Out]BSTR*,VS并没有太多帮助。 - vgru
在C#项目中,我已经使用“添加引用”来包含我的COM C++对象。是的,它创建了一个程序集。我的问题包含使用它的C#代码。但它不处理任何字符串转换。我只是寻找一种正确的方法来处理来自C#的COM函数中的IN/OUT字符串参数。 - Mike

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