结构通过引用传递到非托管C DLL函数后保持不变

问题描述:

我正在写一个非托管的C DLL在C#的包装。在DLL我有以下的方法,它返回指针结构(近门柱年底结构代码):

I'm writing a wrapper in C# for an unmanaged C DLL. In the DLL I have the following method which returns pointer struct (struct code near end of post):

struct zint_symbol *ZBarcode_Create()
{
    struct zint_symbol *symbol = (struct zint_symbol*)calloc(1, sizeof(struct zint_symbol));

    if (!symbol) return NULL;

    symbol->symbology = BARCODE_CODE128;
    strcpy(symbol->fgcolour, "000000");
    strcpy(symbol->bgcolour, "ffffff");
    strcpy(symbol->outfile, "out.png");
    symbol->scale = 1.0;
    symbol->option_1 = -1;
    symbol->option_3 = 928; // PDF_MAX
    symbol->show_hrt = 1; // Show human readable text
    return symbol;
}



我使用的EXTERN方法是:

The extern methods I am using are:

extern struct zint_symbol* ZBarcode_Create(void);
extern int ZBarcode_Encode_and_Buffer(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);
extern int ZBarcode_Encode_and_Print(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);



ZBarcode_Encode_and_Buffer 渲染的图像并将位图在叫我的结构变量位图
ZBarcode_Encode_and_Print 渲染图像并将其保存到文件系统。他们都返回 0 当他们是成功的,并且之间的一个数 1-8 当他们失败。每一次对我来说,他们返回0

ZBarcode_Encode_and_Buffer renders an image and saves the bitmap in a variable in my struct called bitmap. ZBarcode_Encode_and_Print renders an image and saves it to the file system. They both return 0 when they are successful, and a number between 1-8 when they fail. Each time for me, they return 0.

我的C#如下所示:

[DllImport("zint.dll", EntryPoint = "ZBarcode_Create", CallingConvention = CallingConvention.Cdecl)]
public extern static IntPtr Create();

[DllImport("zint.dll", EntryPoint = "ZBarcode_Encode_and_Buffer", CallingConvention = CallingConvention.Cdecl)]
public extern static int EncodeAndBuffer(
 ref zint_symbol symbol,
 string input,
 int length,
 int rotate_angle);

[DllImport("zint.dll", EntryPoint = "ZBarcode_Encode_and_Print", CallingConvention = CallingConvention.Cdecl)]
public extern static int EncodeAndPrint(
 ref zint_symbol symbol,
 string input,
 int length,
 int rotate_angle);

public static void Render()
{
    // call DLL function to generate pointer to initialized struct
    zint_symbol s = (zint_symbol)

    // generate managed counterpart of struct
    Marshal.PtrToStructure(ZintLib.Create(), typeof(zint_symbol));

    // change some settings
    s.symbology = 71;
    s.outfile = "baro.png";
    s.text = "12345";

    String str = "12345";

    // DLL function call to generate output file using changed settings -- DOES NOT WORK --
    System.Console.WriteLine(ZintLib.EncodeAndBuffer(ref s, str, str.Length, 0));

    // DLL function call to generate output file using changed settings -- WORKS --
    System.Console.WriteLine(ZintLib.EncodeAndPrint(ref s, str, str.Length, 0));

    // notice that these variables are set in ZBarcode_Create()?
    Console.WriteLine("bgcolor=" + s.bgcolour + ", fgcolor=" + s.fgcolour + ", outfile=" + s.outfile);

    // these variables maintain the same values as when they were written to in ZBarcode_Create().
    if (s.errtxt != null)
        Console.WriteLine("Error: " + s.errtxt);
    else
        Console.WriteLine("Image size rendered: " + s.bitmap_width + " x " + s.bitmap_height);
}

所有的取值保持不变,即使DLL应该改变他们中的一些,如位图 bitmap_width bitmap_height

All of the variables in s remain unchanged, even though the DLL is supposed to change some of them such as bitmap, bitmap_width, bitmap_height, etc.

我怀疑有 zint_symbol 在内存中;一个我的C#代码和$ B $(由 ZintLib.Create()创建)b另外一个DLL被写入。我的某种的该库工作正常,但是

I suspect that there are two copies of zint_symbol in memory; one that my C# code has (created by ZintLib.Create()) and another one that the DLL is writing to. I am certain that the library works correctly, however.

C结构:

struct zint_symbol {
    int symbology;
    int height;
    int whitespace_width;
    int border_width;
    int output_options;
#define ZINT_COLOUR_SIZE 10
    char fgcolour[ZINT_COLOUR_SIZE];
    char bgcolour[ZINT_COLOUR_SIZE];
    char outfile[FILENAME_MAX];
    float scale;
    int option_1;
    int option_2;
    int option_3;
    int show_hrt;
    int input_mode;
#define ZINT_TEXT_SIZE  128
    unsigned char text[ZINT_TEXT_SIZE];
    int rows;
    int width;
#define ZINT_PRIMARY_SIZE  128
    char primary[ZINT_PRIMARY_SIZE];
#define ZINT_ROWS_MAX  178
#define ZINT_COLS_MAX  178
    unsigned char encoded_data[ZINT_ROWS_MAX][ZINT_COLS_MAX];
    int row_height[ZINT_ROWS_MAX]; /* Largest symbol is 177x177 QR Code */
#define ZINT_ERR_SIZE   100
    char errtxt[ZINT_ERR_SIZE];
    char *bitmap;
    int bitmap_width;
    int bitmap_height;
    struct zint_render *rendered;
};



C#的结构:

The C# struct:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct zint_symbol
    {
        public int symbology;
        public int height;
        public int whitespace_width;
        public int border_width;
        public int output_options;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
        public String fgcolour;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
        public String bgcolour;


        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
        public string errtxt;

        public float scale;

        public int option_1;
        public int option_2;
        public int option_3;
        public int show_hrt;
        public int input_mode;
        public int rows;
        public int width;
        public int bitmap_width;
        public int bitmap_height;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string text;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string primary;

        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 31684)]
        public byte[] encoded_data;

        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 178)]
        public int[] row_height;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string outfile;

        public IntPtr bitmap;
        public IntPtr rendered;
    }



我已经写了一个小的 Windows窗体的例子(该DLL文件都在那里,也的可以在这里找到。库文件(六十一分之十八页介绍了该结构变量)的可以在这里和整个C源代码可用的这里(ZINT-2.4.3.tar.gz)。特别感兴趣的文件是zint.h,LIBRARY.C和datamatrix.c该C源代码是dll的版本相同。

I have written a small Windows forms example (the DLLs are in there and also available here. The library documentation (page 18/61 explains the struct variables) is available here and the entire C source code is available here (zint-2.4.3.tar.gz). Files of particular interest are zint.h, library.c and datamatrix.c. The C source code is the same version of the DLLs.

布局,看起来是结构!不匹配的sizeof(zint_symbol)在C = sizeof的(zint_symbol)在C#

The struct layouts appear to be mismatched. sizeof(zint_symbol) in C != sizeof(zint_symbol) in C#.

您在这里有一个奇怪的错误:

You have an odd mistake here:

[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 25454)]
public byte[] encoded_data;



在哪个.h文件是:

Which in the .h file is:

#define ZINT_ROWS_MAX 178
#define ZINT_COLS_MAX 178
    uint8_t encoded_data[ZINT_ROWS_MAX][ZINT_COLS_MAX];



刚刚宣布它以同样的方式:

Just declare it the same way:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 178 * 178)]
public byte[] encoded_data;



还有一个错误,FILENAME_MAX是260:

One more mistake, FILENAME_MAX is 260:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string outfile;

现在,你应该得到适当的匹配:

Now you should get a proper match:

static void Main(string[] args) {
    var len = Marshal.SizeOf(typeof(zint_symbol));              // 33100
    var offs = Marshal.OffsetOf(typeof(zint_symbol), "errtxt"); // 32984
}

和在C测试程序:

#include <stddef.h>
//...
int main()
{
    size_t len = sizeof(zint_symbol);                // 33100
    size_t offs = offsetof(zint_symbol, errtxt);     // 32984
    return 0;
}