C++;使用结构将字符串转换为C# 有没有一种方法使用C++来将字符串从C++发送到C?我有一个带有图像数据(数据和大小)的结构,在这个结构中,我也希望有来自图像的条形码数据。我曾尝试通过C#中的IntPtr来实现它,但这会返回乱码并通过Stringbuilder实现,但是结构无法编组。有关所有相关代码,请参见下文

C++;使用结构将字符串转换为C# 有没有一种方法使用C++来将字符串从C++发送到C?我有一个带有图像数据(数据和大小)的结构,在这个结构中,我也希望有来自图像的条形码数据。我曾尝试通过C#中的IntPtr来实现它,但这会返回乱码并通过Stringbuilder实现,但是结构无法编组。有关所有相关代码,请参见下文,c#,c++,struct,dllimport,C#,C++,Struct,Dllimport,C#结构 C#导入: 调用C++,我是如何从Itptr:/P>获取字符串的 ImageInfo imInfo = new ImageInfo(); AlgorithmCpp.ScanBarcode(sourceImagePixels, sourceImagePixels.Length, ref imInfo); // wont work with StringBuilder. string stringa = Marshal.PtrToStringAnsi(imInfo.barcodeType

C#结构

C#导入:

调用C++,我是如何从Itptr:/P>获取字符串的

ImageInfo imInfo = new ImageInfo();
AlgorithmCpp.ScanBarcode(sourceImagePixels, sourceImagePixels.Length, ref imInfo); // wont work with StringBuilder.

string stringa = Marshal.PtrToStringAnsi(imInfo.barcodeType); // result: gibberish
stringa = Marshal.PtrToStringAuto(imInfo.barcodeType);        // result: gibberish
stringa = Marshal.PtrToStringBSTR(imInfo.barcodeType);        // result: gibberish
stringa = Marshal.PtrToStringUni(imInfo.barcodeType);         // result: gibberish
stringa = Marshal.PtrToStringUTF8(imInfo.barcodeType);        // result: gibberish

// example what is returned: "\0\0\0\0\0\0\0\0\f\0\0\0"
C++结构:

struct ImageInfo
{
    unsigned char* data;
    int size;

    // String
    //unsigned char* barcodeType; // for IntPtr, return gibberish
    //unsigned char* barcodeData; // for IntPtr, return gibberish

    char* barcodeType; // for StringBuilder
    char* barcodeData; // for StringBuilder
};
如何尝试从C返回字符串++

#define DllExport extern "C" __declspec(dllexport)

DllExport void ScanBarcode(unsigned char* data, int dataLen, ImageInfo& imInfo)
{
    // do stuff to get barcode

    // for IntPtr
    std::string type = symbol->get_type_name();
    std::string data = symbol->get_data();

    imInfo.barcodeType = (unsigned char*)type.c_str();
    imInfo.barcodeData = (unsigned char*)data.c_str();

    // For StringBuilder
    strcpy(imInfo.barcodeData, symbol->get_data().c_str());
    strcpy(imInfo.barcodeType, symbol->get_type_name().c_str());
}
我希望通过上面的代码,我已经让你了解我尝试过的和我想要的。如果您需要任何进一步的信息,请告诉我,我会尽力提供。

A是而不是字符串

将结构更改为:

public struct ImageInfo
{
    public IntPtr data; // image data, works
    public int size;    // image data, works

    // string
    //public IntPtr barcodeType; // return gibberish
    //public IntPtr barcodeData; // return gibberish

    public string barcodeType;
    public string barcodeData;
}

应该工作,因为编译器现在有一个已知值(类型)它可以传递给C++结构。 StringBuilder不起作用,因为这是一个无法转换为字符串的对象,编译器必须知道如何调用.ToString()方法

A是而不是字符串

将结构更改为:

public struct ImageInfo
{
    public IntPtr data; // image data, works
    public int size;    // image data, works

    // string
    //public IntPtr barcodeType; // return gibberish
    //public IntPtr barcodeData; // return gibberish

    public string barcodeType;
    public string barcodeData;
}

应该工作,因为编译器现在有一个已知值(类型)它可以传递给C++结构。 StringBuilder不起作用,因为这是一个无法转换为字符串的对象,编译器必须知道如何调用.ToString()方法

imInfo.barcodeType = (unsigned char*)type.c_str();
imInfo.barcodeData = (unsigned char*)data.c_str();
c_str()
为您提供指向字符串开头的指针,是的。你可以把它传递给一个函数,很好。但是你不能退!谁拥有记忆?它的寿命是多少?什么时候解除分配?C++没有自动内存管理——你不能只返回对象和指针,并期望它们神奇地工作。你甚至不能依赖这种不良行为来产生错误,正如你刚才看到的——你得到的是垃圾;有时你得到了正确的东西,有时是错误的东西,有时你引入了一个可怕的安全漏洞

ScanBarcode
返回时,
类型
数据
被销毁。
c_str()
返回的指针没有指向您认为它指向的数据(无论
c_str()
的内部实现如何)。您需要将该数据复制到共享内存中,并确保它被正确释放。在非托管世界中传递内存并非易事。这就是为什么像C#这样的管理系统和语言最初被设计出来的一个重要原因

设计互操作并不是一件小事。以实际设计良好的C API为例。例如,重要的一点是返回字符串的长度(很少只传递
char*
,而不指定长度;如果不拥有指向的内存,那么这样做完全是疯狂的)。首先,决定谁应该分配和释放内存(这通常应该是相同的)

你已经看到这有点问题了<代码>图像信息由调用方分配。但是
char*
字段是由被调用方分配的!没有办法明智地将对象的生命期限制在C++或C语言的一边(同样,这不是C是问题所在——C++调用方会有同样的问题)。过去处理这个问题的通常方法是使用预先分配的缓冲区,也就是说,
imInfo.barcodeType
不是一个字符串指针,而是一个数组。C#结构将如下所示:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
struct ImageInfo
{
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst=255 /* this must be synchronized with the C++ code! */)]
  public string barcodeType;
}
<> C++侧会做这样的事情(不要在生产代码中使用这个代码,它在某种程度上肯定是错误的——我的C++非常生锈,请与C++程序员商榷):

struct ImageInfo
{
字符条码类型[255];
}
if(type.barcodeType.length()<254)
{
strcpy(imInfo.barcodeType,type.c_str());
}
同样,这是非常幼稚的,可能是错误的。这只是展示了一种在调用方和被调用方之间传递数据的方法。请小心。

< P> C++代码是错误的。< /P>
imInfo.barcodeType = (unsigned char*)type.c_str();
imInfo.barcodeData = (unsigned char*)data.c_str();
c_str()
为您提供指向字符串开头的指针,是的。你可以把它传递给一个函数,很好。但是你不能退!谁拥有记忆?它的寿命是多少?什么时候解除分配?C++没有自动内存管理——你不能只返回对象和指针,并期望它们神奇地工作。你甚至不能依赖这种不良行为来产生错误,正如你刚才看到的——你得到的是垃圾;有时你得到了正确的东西,有时是错误的东西,有时你引入了一个可怕的安全漏洞

ScanBarcode
返回时,
类型
数据
被销毁。
c_str()
返回的指针没有指向您认为它指向的数据(无论
c_str()
的内部实现如何)。您需要将该数据复制到共享内存中,并确保它被正确释放。在非托管世界中传递内存并非易事。这就是为什么像C#这样的管理系统和语言最初被设计出来的一个重要原因

设计互操作并不是一件小事。以实际设计良好的C API为例。例如,重要的一点是返回字符串的长度(很少只传递
char*
,而不指定长度;如果不拥有指向的内存,那么这样做完全是疯狂的)。首先,决定谁应该分配和释放内存(这通常应该是相同的)

你已经看到这有点问题了<代码>图像信息由调用方分配。但是
char*
字段是由被调用方分配的!没有办法明智地限制对象的生命周期到C++或C的边(同样,这不是C是问题所在)——C++调用方会有同样的问题。
struct ImageInfo
{
  char barcodeType[255];
}

if (type.barcodeType.length() < 254) 
{
  strcpy(imInfo.barcodeType, type.c_str());
}