传递到非托管C DLL函数时,C#struct变量保持为null

时间:2014-08-29 19:13:29

标签: c# c pinvoke dllimport

问题:

我正在为非托管C DLL编写C#包装器。 DLL包含结构zint_symbol,其中包含变量char[] *bitmap。在我的C#结构中,我有public byte[] bitmap;

此结构传递给外部函数ZBarcode_Encode_and_Buffer,该函数应该呈现PNG图像并将位图数据写入bitmap中的zint_symbol

当我调用ZBarcode_Encode_and_Buffer并检查bitmap时,它仍为 null

事实上,我的C#结构中的每个变量都应该由DLL写入 null

我尝试过的事情:

  1. bitmap编组为具有非常大常数的固定大小数组,即

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

    ...产生SystemAccessViolation

    An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll
    
    Additional information: Attempted to read or write protected memory. This is often an indication     that other memory is corrupt.
    
  2. ibtmap的类型更改为char[]string。这没有任何改变。

  3. [In,Out]装饰器添加到我传递给C#函数的struct参数中。

  4. bitmap的类型从byte[]更改为IntPtr

  5. 我不能做的事:

    我似乎无法编译库,尽管有源(该项目是开源但多年前已废弃)。这意味着我无法更改C代码。

    代码/工作示例

    一个小而完整的工作示例 can be downloaded here

    包含我的struct的C#类:

    class ZintLib
    {
        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 = 256)]
            public string outfile;
    
            public float scale;
            public int option_1;
            public int option_2;
            public int option_3;
            public int show_hrt;
    
            public int input_mode;
    
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string text;
    
            public int rows;
            public int width;
    
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string primary;
    
            [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 25454)]
            public byte[] encoded_data;
    
            [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 178)]
            public int[] row_height;
    
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string errtxt;
    
            public byte[] bitmap;
    
            public int bitmap_width;
            public int bitmap_height;
            public IntPtr rendered;
        }
    
        [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(
          [In, Out] ref zint_symbol symbol,
         String input,
         int length,
         int rotate_angle);
    }
    

    调用EncodeAndBuffer的函数:

            // call DLL function to generate pointer to initialized struct
            ZintLib.zint_symbol s = (ZintLib.zint_symbol)
    
            // generate managed counterpart of struct
            Marshal.PtrToStructure(ZintLib.Create(), typeof(ZintLib.zint_symbol));
    
            // change some settings
            s.symbology = 71;
            s.outfile = "datamatrix.png";
    
            // DLL function call to generate output file using changed settings -- WORKS --
            //System.Console.WriteLine(ZintLib.EncodeAndPrint(ref s, "12345", 5, 0));
    
            // DLL function to generate data in s.bitmap, s.bitmapheight, s.bitmapwidth -- DOES NOT WORK managed struct is unaltered --
            System.Console.WriteLine(ZintLib.EncodeAndBuffer(ref s, (String)"12345", 5, 0));
    
            if (s.bitmap == null)
                Console.WriteLine("bitmap is null.");
            else
                Console.WriteLine("bitmap is not null.");
    

    C:

    中的结构和导出方法
    struct zint_symbol {
        int symbology;
        int height;
        int whitespace_width;
        int border_width;
        int output_options;
        char fgcolour[10];
        char bgcolour[10];
        char outfile[256];
        float scale;
        int option_1;
        int option_2;
        int option_3;
        int show_hrt;
        int input_mode;
        unsigned char text[128];
        int rows;
        int width;
        char primary[128];
        unsigned char encoded_data[178][143];
        int row_height[178]; /* Largest symbol is 177x177 QR Code */
        char errtxt[100];
        char *bitmap;
        int bitmap_width;
        int bitmap_height;
        struct zint_render *rendered;
    };
    
    #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(_MSC_VER)
    #  if defined (DLL_EXPORT) || defined(PIC) || defined(_USRDLL)
    #    define ZINT_EXTERN __declspec(dllexport)
    #  elif defined(ZINT_DLL)
    #    define ZINT_EXTERN __declspec(dllimport)
    #  else
    #    define ZINT_EXTERN extern
    #  endif
    #else
    #  define ZINT_EXTERN extern    
    #endif
    
    ZINT_EXTERN struct zint_symbol *ZBarcode_Create(void);
    ZINT_EXTERN void ZBarcode_Clear(struct zint_symbol *symbol);
    ZINT_EXTERN void ZBarcode_Delete(struct zint_symbol *symbol);
    
    ZINT_EXTERN int ZBarcode_Encode(struct zint_symbol *symbol, unsigned char *input, int length);
    ZINT_EXTERN int ZBarcode_Encode_File(struct zint_symbol *symbol, char *filename);
    ZINT_EXTERN int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle);
    ZINT_EXTERN int ZBarcode_Encode_and_Print(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);
    ZINT_EXTERN int ZBarcode_Encode_File_and_Print(struct zint_symbol *symbol, char *filename, int rotate_angle);
    
    ZINT_EXTERN int ZBarcode_Render(struct zint_symbol *symbol, float width, float height);
    
    ZINT_EXTERN int ZBarcode_Buffer(struct zint_symbol *symbol, int rotate_angle);
    ZINT_EXTERN int ZBarcode_Encode_and_Buffer(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);
    ZINT_EXTERN int ZBarcode_Encode_File_and_Buffer(struct zint_symbol *symbol, char *filename, int rotate_angle);
    
    ZINT_EXTERN int ZBarcode_ValidID(int symbol_id);
    
    #ifdef __cplusplus
    }
    #endif /* __cplusplus */
    
    #endif /* ZINT_H */
    

    注意:提出了类似问题,但在this thread中从未解决过。我已经在这个问题上摸不着头脑了一个星期。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

您必须将bitmap成员声明为IntPtr并手动编组。

如果调用者使用Marshal.AllocHGlobal分配内存。然后使用Marshal.Copy在非托管内存和位图的托管表示之间进行复制。或者固定代表位图的托管字节数组。

如果被调用者分配内存,那么您只需要Marshal.Copy从非托管复制到托管。

这是一个非常复杂的界面,似乎有其他错误似乎是合理的。我只是查看了bitmap字段,因为它是您所询问的内容。