vendredi 29 août 2014

C# struct variables remain null when passed into unmanaged C DLL functions


Vote count:

0




Problem:


I am writing a C# wrapper for an unmanaged C DLL. The DLL contains a struct zint_symbol, which contains a variable char[] *bitmap. In my C# struct I have public byte[] bitmap;.


This struct is passed in to an external function ZBarcode_Encode_and_Buffer which is supposed to render a PNG image and write the bitmap data to bitmap in zint_symbol.


When I invoke ZBarcode_Encode_and_Buffer and check bitmap, it remains null.


In fact, every variable in my C# struct that is supposed to be written by the DLL remains null.


What I've tried:




  1. Marshalling bitmap as a fixed-size array with a very large constant, i.e.,



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


    ...which yields a 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. Changing the type of ibtmap to char[] and string. This changed nothing.




  3. Adding the [In,Out] decorator to the struct parameter I am passing into my C# function.




  4. Changing the type of bitmap from byte[] to IntPtr.




What I cannot do:


I cannot seem to compile the library, despite having the source (the project is open source but abandoned years ago). This means I cannot change the C code.


Code/Working example


I left only certain things in for brevity. A small but complete working example can be downloaded here .


C# class containing my struct:



class ZintLib
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct zint_symbol
{
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);
}


The function calling 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.");


The struct and export methods in 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 */


Note: A similar question was asked but never resolved in this thread. I've been scratching my head over this for a week. Any ideas?



asked 32 secs ago

josh

1,293






C# struct variables remain null when passed into unmanaged C DLL functions

Aucun commentaire:

Enregistrer un commentaire