2

我获得了已编译为 DLL 的 C 代码。然后,我在 VC++ 中创建了一个包装器,它调用此代码中的函数。到目前为止一切正常。我无法将 C# stringbuilder (char*) 从使用此包装器的 C# 代码传递给 C++ 代码。

到目前为止,我有一个用 VC++ 编写的包装类,它有这个函数调用:

void Wrapper::ReadStream(char* buffer, int* size)
{
    int req_sz;
    read_stream(opts, req_sz, req, buffer); //This calls the C DLL, this part works.
} 

在尝试调用 C++ 包装函数 ReadStream 时,我的 C# 代码出现问题。在四处寻找类似问题后,我发现为了将字符串从 C# 传递到 C++(它将寻找一个 char*),应该传递一个 stringbuilder,所以我尝试了:

C#代码:

...
Wrapper wrap = new Wrapper()
...

int bufferSize = 48;
StringBuilder buffer = new StringBuilder(bufferSize);
wrap.ReadStream(buffer, ref bufferSize);

但是代码不会编译,因为 C# 认为函数定义需要 sbyte*。我读过这是因为 C# 字符是 unicode(2 个字节),而 C++ 字符是单字节字符,但建议的解决方案是传递一个 StringBuilder。

我见过很多解决方案,其中 C# 代码将 stringbuilder 直接传递给 DLL,但找不到将 stringbuilder 传递给 C++ 包装类的解决方案。

4

2 回答 2

1

您绝对可以将 StringBuilder 传递给 C++ 端,只需将 Wrapper::ReadStream 签名更改为:

void Wrapper::ReadStream(LPWSTR buffer, int* size)

顺便说一句,既然你说你有 C 代码,我建议修改它以便你可以直接从 C# 调用它(因为 C 是 C++ 的子集,C 代码通常也是 C++ 代码,你可以添加 C++ 功能像上课一样)。这样你就可以避免使用包装器,这总是很痛苦。

当您使用它时,我还建议将其修改为使用 Unicode 字符串而不是 ANSI 字符串(除非有些东西需要 ANSI 字符串)。

最后,我建议使用 COM 让 C# 端和 C++ 端相互通信。然后 ReadStream 方法将位于 IDL 接口中,例如:

[object, uuid(2C5B0D36-0B34-4FEE-A0B8-B10F7A019A6D)]
interface ISomeObject : IUnknown
{
    HRESULT ReadStream([out, retval] BSTR* pbstrBuffer);
}

BSTR 是 COM 的字符串类型(它是 Unicode)。C#端会看到如下界面:

interface ISomeObject
{
    string ReadStream();
}

不需要“大小”参数,因为您正在返回一个新字符串,而不是填充传入的缓冲区(存在缓冲区可能太小而无法容纳结果的问题)。

如果您以前没有使用过 COM,那么它的学习曲线可能会很陡峭,但如果您打算像这样进行大量互操作,那么它是值得的。

于 2012-10-24T14:30:47.567 回答
1

您可以将 C# unicode 字符串传递给std::wstring,然后在 c++ 代码中您可以将std::wstring 转换为 std::string并传递给 C-API。

或者您可以使用Encoding ASCII GetBytes并在 C# 代码中获取 Byte[],将数组传递给 c++,将其转换为以空字符结尾的字符串并将其传递给 C-API。我可能会选择第二种选择。

于 2012-10-24T13:57:51.437 回答