C# P/Invoke 2 dimensional array - c#

I am trying to call a C function from C# code:
typedef char IPTriggerNameType[256];
typedef unsigned long COMM_HANDLE;
typedef BYTE GUID_TYPE[16];
typedef long LONGINT;
typedef struct {
GUID_TYPE Guid;
IPTriggerNameType Name;
}IPCAM_GENERIC_EVENT_ID;
typedef struct {
IPCAM_GENERIC_EVENT_ID EventId;
LONGINT RelatedTriggerId;
LONGINT ObsoleteEvent;
}IPCAM_GENERIC_EVENT_INFO;
typedef struct
{
LONGINT NumOfEvents;
IPCAM_GENERIC_EVENT_INFO *GenericEventsList;
}VID_CHANNEL_GENERIC_EVENTS_STRUCT;
int __stdcall GetGenericEvents(
/* Inputs: */
COMM_HANDLE Handle,
LONGINT MaxNumOfChannelsInTable,
LONGINT MaxNumOfEventsPerChannel,
/* Outputs: */
LONGINT *NumOfChannels,
VID_CHANNEL_GENERIC_EVENTS_STRUCT *ChannelsEventsTable);
and the C# equivalent is as follows:
[StructLayout(LayoutKind.Sequential)]
public struct IPCAM_GENERIC_EVENT_ID
{
[MarshalAs(UnmanagedType.LPArray, SizeConst = 16)]
public byte[] Guid;
[MarshalAs(UnmanagedType.LPArray, SizeConst = 256)]
public char[] Name;
};
[StructLayout(LayoutKind.Sequential)]
public struct IPCAM_GENERIC_EVENT_INFO
{
public IPCAM_GENERIC_EVENT_ID EventId;
public int RelatedTriggerId;
public int ObsoleteEvent;
}
[StructLayout(LayoutKind.Sequential)]
public struct VID_CHANNEL_GENERIC_EVENTS_STRUCT
{
public int NumOfEvents;
[MarshalAs(UnmanagedType.LPArray, SizeConst = 100)]
public IPCAM_GENERIC_EVENT_INFO[] GenericEventsList;
}
[DllImport(dllName)]
public static extern int GetGenericEvents(
/* Inputs: */
int Handle,
int MaxNumOfChannelsInTable,
int MaxNumOfEventsPerChannel,
/* Outputs: */
out int NumOfChannels,
out VID_CHANNEL_GENERIC_EVENTS_STRUCT[] ChannelsEventsTable);
int numOfChannels = 16, actualNumOfChannels = 0;
int maxNumOfEvents = 100;
VID_CHANNEL_GENERIC_EVENTS_STRUCT[] genericEventsList = new VID_CHANNEL_GENERIC_EVENTS_STRUCT[numOfChannels];
for (int i = 0; i < numOfChannels; i++)
{
genericEventsList[i].GenericEventsList = new IPCAM_GENERIC_EVENT_INFO[maxNumOfEvents];
}
GetGenericEvents(conn, numOfChannels, maxNumOfEvents, out actualNumOfChannels, out genericEventsList);
when calling the C# method I get exception which crashes the application:
Managed Debugging Assistant 'FatalExecutionEngineError' has detected a
problem in 'My.exe'.
Additional information: The runtime has encountered a fatal error. The
address of the error was at 0x72a6cf41, on thread 0x5a98. The error
code is 0xc0000005. This error may be a bug in the CLR or in the
unsafe or non-verifiable portions of user code. Common sources of this
bug include user marshaling errors for COM-interop or PInvoke, which
may corrupt the stack.
What am I doing wrong ?

The field:
VID_CHANNEL_GENERIC_EVENTS_STRUCT.GenericEventsList
is a pointer, declared as:
IPCAM_GENERIC_EVENT_INFO *GenericEventsList
But you are declaring it as an array, included in the struct:
[MarshalAs(UnmanagedType.LPArray, SizeConst = 100)]
public IPCAM_GENERIC_EVENT_INFO[] GenericEventsList;
You may try to use an IntPtr and Marshal.AllocHGlobal. Check this out: How use pinvoke for C struct array pointer to C#

Related

converting c++ API struct to c#

I am trying to convert c++ api example to c#. but I can not find the way of struct pointer in struct by the way struct has string types. Here is c++ structs and functions
struct AuthParam { char server_ip[32]; char username[50]; char password[50]; };
struct CameraInfo { int index; char devicename[100]; char smallrtsp[1000]; char bigrtsp[1000]; };
struct SingleDevice { char deviceid[50]; char devicename[100]; int flag_onuse; int cameralist_size; CameraInfo* cameralist; };
struct DeviceList { int listsize; SingleDevice* singledevicelist; };
typedef int (WINAPI capi_init)(void);
typedef int (WINAPI capi_disabled)(void);
typedef int (WINAPI capi_GetServerTimeCode)(char* server_ip, unsigned int* timecode);
typedef int (WINAPI GetDevicelist)(AuthParam auth_para, DeviceList* devicelist);
and this is my c# code but I can not find the way of defining struct pointer in struct I got "
Error CS0208 Cannot take the address of, get the size of, or declare a pointer to a managed type ('Form1.CameraInfo')" error.
public struct AuthParam
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string server_ip;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string username;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string password;
};
[StructLayout(LayoutKind.Sequential)]
public struct CameraInfo
{
public int index;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string devicename;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1000)]
public string smallrtsp;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1000)]
public string bigrtsp;
};
[StructLayout(LayoutKind.Sequential)]
public struct SingleDevice
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string deviceid;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string devicename;
public int flag_onuse;
public int cameralist_size;
public CameraInfo *cameralist;
};
[StructLayout(LayoutKind.Sequential)]
public unsafe struct DeviceList
{
public int listsize;
public SingleDevice *singledevicelist;
};
[DllImport("c:\\lib\\api_client.dll")] public static extern int capi_init();
[DllImport("c:\\lib\\api_client.dll")] public static extern int capi_disabled();
[DllImport("c:\\lib\\api_client.dll")] public static extern int capi_GetServerTimeCode(string ip, ref uint timecode);
[DllImport("c:\\lib\\api_client.dll")] public static extern int GetDevicelist (AuthParam auth_para,ref DeviceList devicelist);
is there any way to achieve this convertion?
i think this error because of the different nature of c++ (un-managed code) and c# (managed code), so maybe using System.IntPtr as a pointer to your camera struct.
please consider this question here, and you can find about P/Invoke Interop Assistant which is an open source tool to convert your code from the un-managed code to a managed C# code. with a small blog article about C++/C# interoperability

C struct and use C dll in C#

everyone, I'm newbie in C#, and I have a problem with using "C" dll in C#, below is the C side code which work fine.
// myCode.h
typedef struct _SubABC
{
unsigned short WordCount;
unsigned char *WordData;
unsigned char SpeedUp;
} SubABC;
typedef struct _ABC
{
unsigned char SubFontNum;
SubABC subABC[5];
} ABC
extern __declspec(dllimport) int __stdcall MY_SetSth(unsigned char SerialNum, ABC *pABC);
//myCode.c
ABC myFun = { '\0' };
unsigned char text_c[] =
{
0x00,0x27,0xff,0xA5,0xC3, 0x00,0x27,0xff,0xA6,0x26, 0x00,0x23,0xff,0xA7,0xAE, 0x00,0x27,0xff,0xBA,0x7E,
0x00,0x27,0xff,0xC1,0x52, 0x00,0x27,0xff,0xAC,0xF9, 0x00,0x27,0xff,0x20,0x00,0x27,0xff,0x31, 0x00,0x27,0xff,0x20, 0x00,0x27,0xff,0xA4,0xC0, 0x00,0x27,0xff,0xC4,0xC1,
};
myFun.SubFontNum = 1;
myFun.subMABC[0].WordCount = sizeof(text_c);
myFun.subMABC[0].WordData = text_c;
myFun.subMABC[0].SpeedUp = 0;
int retvalue = MY_SetSth(1, &myFun);
and my C# code is below
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct SubABC
{
public ushort WordCount;
[MarshalAs(UnmanagedType.LPArray)]
public byte[] WordData;
public byte SpeedUp;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ABC
{
public byte SubFontNum;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public SubABC[] subABC;
}
[DllImport("myDLL.dll", CharSet = CharSet.Ansi)]
public extern static int MY_SetSth(byte SerialNum, ref ABC pABC);
ABC myFun = new ABC();
ABC.subABC = new SubABC[5];
unsigned char text_c[] =
{
0x00,0x27,0xff,0xA5,0xC3, 0x00,0x27,0xff,0xA6,0x26, 0x00,0x23,0xff,0xA7,0xAE, 0x00,0x27,0xff,0xBA,0x7E,
0x00,0x27,0xff,0xC1,0x52, 0x00,0x27,0xff,0xAC,0xF9, 0x00,0x27,0xff,0x20,0x00,0x27,0xff,0x31, 0x00,0x27,0xff,0x20, 0x00,0x27,0xff,0xA4,0xC0, 0x00,0x27,0xff,0xC4,0xC1,
};
myFun.SubFontNum = 1;
myFun.subMABC[0].WordCount = (ushort)text_c.Length;
myFun.subMABC[0].WordData = text_c;
myFun.subMABC[0].SpeedUp = 0;
int retvalue = MY_SetSth(1, ref myFun);
I always get TypeLoadException: Cannot marshal field 'WordData' of type 'subABC': Invalid managed/unmanaged type combination (Array fields must be paired with ByValArray or SafeArray), because WordData is unknown size, I can't use ByValArray, and SafeArray get AccessViolationException: Attempted to read or write protected memory
I try to use IntPtr like below
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct SubABC
{
public ushort WordCount;
public IntPtr WordData;
public byte SpeedUp;
}
ABC.subABC[0].WordData = Marshal.AllocHGlobal(text_c.Length); ;
Marshal.Copy(text_c, 0, ABC.subABC[0].WordData, text_c.Length);
int retvalue = MY_SetSth(1, ref myFun);
I get error message AccessViolationException: Attempted to read or write protected memory
Can anyone help me? thank a lot.

How to use a DLL and a .cs file in Delphi

I have a DLL written in C++ (help file says so)
I have this .cs file that holds the function names and looks something like this:
*// -------------- Part of MXIO.cs File -----
//#define _NET_WINCE
//==========================================================================================
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace MOXA_CSharp_MXIO
{
class MXIO_CS
{
public const int SUPPORT_MAX_SLOT = 16;
public const int SUPPORT_MAX_CHANNEL = 64;
public const int SupportMaxChOfBit = SUPPORT_MAX_CHANNEL>>3;
//
#if _NET_WINCE
[StructLayout(LayoutKind.Explicit, Size = 4)]
#else
[StructLayout(LayoutKind.Explicit, Size = 4, Pack = 1)]
#endif
//V1.2 OPC Tag DATA Struct
#if _NET_WINCE
[StructLayout(LayoutKind.Sequential)]
#else
[StructLayout(LayoutKind.Sequential, Pack = 1)]
#endif
public struct _IOLOGIKSTRUCT
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] BytMagic;
public UInt16 wVersion; // struct define of version 1.0.0
public UInt16 wLength;
public UInt16 wHWID; // for user to know which API to Read/write
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] dwSrcIP;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] BytSrcMAC;
public byte BytMsgType; // for AP side to known what kind of Message return
public UInt16 wMsgSubType;
//------------------------
// tag timestamp
public UInt16 wYear;
public byte BytMonth;
public byte BytDay;
public byte BytHour;
public byte BytMin;
public byte BytSec;
public UInt16 wMSec;
//-------------------------
public byte BytLastSlot; //add to notice the last slot, Range 0-16, 0=>myself only
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SUPPORT_MAX_SLOT)]
public byte[] BytLastCh;
//-------------------------
// support up to 16 slots and 64 channels //size:5408 bytes
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SUPPORT_MAX_SLOT * SUPPORT_MAX_CHANNEL)]
public byte[] BytChType; // channel I/O type
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SUPPORT_MAX_SLOT)]
public UInt16[] wSlotID; // Slot Module ID
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SUPPORT_MAX_SLOT * SupportMaxChOfBit)]
public byte[] BytChNumber; // bitwised¡A1=Enable¡A0=Disable
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SUPPORT_MAX_SLOT * SUPPORT_MAX_CHANNEL)] //
public _ANALOG_VAL[] dwChValue;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SUPPORT_MAX_SLOT * SupportMaxChOfBit)]
public byte[] BytChLocked; // bitwised, 0=free, 1=locked
}
//
#if _NET_WINCE
[StructLayout(LayoutKind.Sequential)]
#else
[StructLayout(LayoutKind.Sequential, Pack = 1)]
#endif
public struct _ACTDEV_IO
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] BytSrcMAC;
public Int32 iHandle;
}
//
#if _NET_WINCE
[StructLayout(LayoutKind.Sequential)]
#else
[StructLayout(LayoutKind.Sequential, Pack = 1)]
#endif
public struct _MODULE_LIST
{
public UInt16 nModuleID; //Module ID of device
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] szModuleIP; //Save IP address of device
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] szMAC; //Save MAC address of device
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] szModuleIP1; //Save 2nd IP address of device
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] szMAC1; //Save 2nd MAC address of device
public byte bytLanUse; //0 -> Lan0, 1 -> Lan1
}
public delegate void pfnCALLBACK(IntPtr bytData, UInt16 wSize);
public delegate void pfnTagDataCALLBACK( _IOLOGIKSTRUCT[] ios, UInt16[] wMutex);
/**********************************************/
/* */
/* Ethernet Module Connect Command */
/* */
/**********************************************/
[DllImport("MXIO_NET.dll")]
public static extern int MXEIO_Init();
[DllImport("MXIO_NET.dll")]
public static extern void MXEIO_Exit();
[DllImport("MXIO_NET.dll")]
public static extern int MXEIO_Connect(byte[] szIP, UInt16 wPort, UInt32 dwTimeOut, Int32[] hConnection);
[DllImport("MXIO_NET.dll")]
public static extern int MXEIO_Disconnect( Int32 hConnection );
[DllImport("MXIO_NET.dll")]
public static extern int MXEIO_CheckConnection( Int32 hConnection, UInt32 dwTimeOut, byte[] bytStatus );
/***********************************************/
/* */
/* General Command */
/* */
/***********************************************/
[DllImport("MXIO_NET.dll")]
public static extern int MXIO_GetDllVersion();
[DllImport("MXIO_NET.dll")]
public static extern int MXIO_GetDllBuildDate();
/*************************************************/
/* */
/* Error Code */
/* */
/*************************************************/
public const int MXIO_OK = 0;
public const int ILLEGAL_FUNCTION = 1001;
public const int ILLEGAL_DATA_ADDRESS = 1002;
/*************************************************/
/* */
/* Data Format Setting */
/* */
/*************************************************/
/* Data length define */
public const int BIT_5 = 0x00;
public const int BIT_6 = 0x01;
public enum MXIO_ModuleDataIndex: int
{
//---------------------------------------------------------------------------
MX_ML_MODULE_LIST_SIZE = 47,
MX_ML_INDEX_WHWID = 0,
MX_ML_INDEX_SZIP0 = 2, //SIZE:16 (STRING)
MX_ML_INDEX_SZMAC0 = 18, //SIZE:6 (STRING)
MX_ML_INDEX_SZIP1 = 24, //SIZE:16 (STRING)
MX_ML_INDEX_SZMAC1 = 40, //SIZE:6 (STRING)
MX_ML_INDEX_BYTLANUSE = 46
};
//---------------------------------------------------------------------------
}
}*
I'm trying to access any of the functions inside the DLL. Here is the Delphi code:
type
TMyCall = function: integer; stdcall;
const
MYDLL = 'D:\DelphiProjects\DLL_Read\MXIO_NET.dll';
procedure TForm2.btnFncClick(Sender: TObject);
var
i,j,k: integer;
Handle: THandle;
mCall : TMyCall;
begin
// Load the library
Handle := LoadLibrary(MYDLL);
// If succesful ...
if Handle <> 0 then
begin
// Assign function from the DLL to the
// function variable mCall
#mCall := GetProcAddress(Handle, 'MXIO_GetDllVersion');
// If successful
if #mCall <> nil then
begin
Label3.Caption:= 'DLL version =' + IntToStr(mCall);
end
else
Label3.Caption:= 'Function Not found';
// Unload library
FreeLibrary(Handle);
end
else
Label3.Caption:= 'Version Handle = 0';
end;
Problem: GetProcAddress fails and returns nil.
I tried to cut the code into minimal and complete portion, hope I could do this time. Now I'm thinking to convert the .cs file (at least some part of it) into a Delphi unit and call the DLL functions from there. I wonder if anyone had experience on this? I'd appreciate any help
The question is somewhat confused. There is a huge amount of C# code that has no corresponding Delphi code. One wonders if the Delphi code really does exhibit the problem that you claim it does.
Anyway, on the assumption that the GetProcAddress call that you show does fail, then the question is easy enough to answer. GetProcAddress has two failure modes:
The module handle supplied is not valid.
The procedure name supplied is not valid.
We can rule out item 1 since the module handle was returned by a call to LoadLibrary. If LoadLibrary succeeds then we know that we have a valid module handle.
So, the only conclusion is that the procedure name supplied is not valid. Which means that the DLL that you have loaded does not export a function named MXIO_GetDllVersion. You can confirm this yourself by calling GetLastError immediately after GetProcAddress returns nil. When you do so you will get the value 127 which is ERROR_PROC_NOT_FOUND.
You can confirm this by inspecting the function names that the DLL exports. Use a tool such as Dependency Walker to do so.
One other minor comment on your Delphi code. You've used THandle for the module handle, but that is the wrong type. It won't affect behaviour but it is semantically wrong. Use HMODULE.

consume c# array of structs using c++ unmanaged Dll

as i am new to the unmanaged world, and after a success test of interacting with c++ DLL on a simple task,
i am now trying to consume in c#, data manipulated by c++ via an array of struct
i have also tried to wrap the struct[] within another struct to simplify the marshal but i did not succeed in any way.
what is the correct (and most efficient performance wise) way to handle the data returned from c++ given the code below.
C#
[StructLayout(LayoutKind.Sequential)]
public struct chars
{
public int V;
//[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 10)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] testStr;
}
[DllImport("ExportStructArr.dll", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void dodata(int requestedMasterArrLength, int requestedStringSize,[MarshalAs(UnmanagedType.LPArray), Out()] chars[] Cars);
//tried also this signature
public static extern void dodata(
int requestedMasterArrLength,
int requestedStringSize,
out IntPtr chars);
c++
#ifdef EXPORTSTRUCTARR_EXPORTS
#define EXPORTSTRUCTARR_API extern "C" __declspec(dllexport)
typedef struct {
int Id;
char *StrVal;
}Unit;
EXPORTSTRUCTARR_API void dodata(int requestedMasterArrLength,int requestedStringSize, Unit **UntArr)
{
int ccountr,count;
count=0;
*UntArr = (Unit*)LocalAlloc(0, requestedMasterArrLength * sizeof(Unit));
Unit *CurU = *UntArr;
while(count!= requestedMasterArrLength)
{
char dummyStringDataObject[]= "abcdefgHi";
CurU[count].StrVal = NULL;
dummyStringDataObject[0] = count+'0';
CurU[count].Id = count;
CurU[count].StrVal= (char*) LocalAlloc(0,(sizeof(char)* requestedStringSize));
ccountr=0;
while(ccountr!= requestedStringSize){
CurU[count].StrVal[ccountr] = dummyStringDataObject[ccountr];
++ccountr;
}
++count;
}
}

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

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:
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.
Changing the type of ibtmap to char[] and string. This changed nothing.
Adding the [In,Out] decorator to the struct parameter I am passing into my C# function.
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
A small but complete working example can be downloaded here.
C# class containing my struct:
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);
}
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?
You are going to have to declare the bitmap member as IntPtr and marshal it manually.
If the caller allocates the memory do so with Marshal.AllocHGlobal. And then use Marshal.Copy to copy between the unmanaged memory and your managed representation of the bitmap. Or pin the managed byte array that represents the bitmap.
If the callee allocates the memory then you just need Marshal.Copy to copy from unmanaged to managed.
It's quite a complex interface and it seems plausible that there will be other errors. I've just looked at the bitmap field since it's what you asked about.

Categories

Resources