2012-10-24 50 views
2

我被赋予了编译为DLL的C代码。然后我用VC++创建了一个包装器,它在这段代码中调用函数。到目前为止,一切正常。我无法将C#stringbuilder(char *)从使用此包装的C#代码传递到C++代码。将C#字符串构建器传递给C DLL的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#代码中的问题,而试图调用C++封装函数ReadStream

。四处寻找类似的问题后,我发现,为了从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#代码直接将字符串构建器传递给DLL,但无法找到将字符串构建器传递给C++包装类的解决方案。

回答

1

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

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

1

你绝对可以通过一个StringBuilder到C++的一面,只是改变了包装:: ReadStream签名:

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

顺便说一句,既然你说你有C代码,我建议修改它所以你可以直接从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,它可能会有一个陡峭的学习曲线,但如果您计划像这样做很多互操作性,它是值得的。

+0

是否有某个库需要导入才能使用LPWSTR? – sdm350

+0

@Azkar LPWSTR只是'const wchar_t *'的同义词(它在''中定义)。 – user1610015

+0

Gotcha。谢谢你的回答,我实际上最终走向了一个不同的方向,虽然我实际上并不想用unicode字符来填充缓冲区,我通过网络接收的数据只是带符号的字符(一个字节) 。我最终发送了C++一个sbyte缓冲区指针,该指针适用于我想要执行的操作。我考虑过COM的建议,但现在根本没有时间去改变它,而且我们有一些其他的包装工具可以这样工作。 – sdm350

相关问题