Pass c# structure array to c++ - c#

I work on c++ dll and have any problem!
my header file is like this
struct ST_DevInfo
{
EN_DevType de_type;
int screen_width;
int screen_height;
char dev_name[256];
char id[14];
char sboox_version[16];
char fpga_version[16];
};
extern "C" __declspec(dllexport) int CB_GetDeviceList(ST_DevInfo* buff,int length);
and c++ code
int CB_GetDeviceList(ST_DevInfo* buff,int length)
{
buff = (ST_DevInfo *)malloc(sizeof(ST_DevInfo) * length);
return GetDeviceList(buff, length);
}
now i use this function in c# like this
[StructLayout(LayoutKind.Sequential)]
struct ST_DevInfo
{
[MarshalAs(UnmanagedType.I4)]
public EN_DevType de_type;
[MarshalAs(UnmanagedType.I4)]
public int screen_width;
[MarshalAs(UnmanagedType.I4)]
public int screen_height;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 256)]
public char[] dev_name;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 14)]
public char[] id;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 16)]
public char[] sboox_version;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 16)]
public char[] fpga_version;
};
[DllImport(dllName, EntryPoint = "CB_GetDeviceList", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public static extern
int CB_GetDeviceList([MarshalAs(UnmanagedType.LPArray)] ref ST_DevInfo[] buff,
int length);
and finally i use this function in my program like this
ST_DevInfo[] buff = new ST_DevInfo[dev_length];
int ret = BBIA.CB_GetDeviceList( ref buff, dev_length);
but after retrieve from CB_GetDeviceList my buff variable assigned but not has any value(contain 0x00). i test it in c++ and it work fine!!
i think a have problem on this line
buff = (ST_DevInfo *)malloc(sizeof(ST_DevInfo) * length);

In your C# code you're doing this:
ST_DevInfo[] buff = new ST_DevInfo[dev_length];
int ret = BBIA.CB_GetDeviceList( ref buff, dev_length);
Which is allocating an array, and passing that (by a double pointer since you have ref), to the C++ code.
In your C++ code you are doing:
int CB_GetDeviceList(ST_DevInfo* buff,int length)
{
buff = (ST_DevInfo *)malloc(sizeof(ST_DevInfo) * length);
return GetDeviceList(buff, length);
}
Which is taking an array (and not as a double pointer) and changing that (local) pointer to point to some new memory. So your original array from C# will never be touched by the C++ code.
First, remove the malloc call completely. Then change your pinvoke to something like:
[DllImport( ... )]
public static extern int CB_GetDeviceList( [In, Out] ST_DevInfo[] buff, int length );
And call as before but without the ref. In, Out is needed to tell the marshaller that you expect the pinvoke call to modify the data. They are not necessary in every case, but in your case I'm not a 100% sure so I'd keep them just in case.

Related

Array elements gets memory override leading to access violation exception

From the beginning, sorry for the weird title, but i really don't know how to describe this problem in short phrase.
I'm trying to wrapp a c++ DLL using pinvoke method. I have this function:
C++ header:
int32_t __cdecl ShowAllCharacters(Uint32Array *Image);
C#:
[DllImport(#"x86\OCR.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int ShowAllCharacters(ref IntPtr image);
Where IntPtr image leads to following struct:
C++ header:
typedef struct {
int32_t dimSizes[2];
uint32_t elt[1];
} Uint32ArrayBase;
typedef Uint32ArrayBase **Uint32Array;
C#:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct Uint32Array
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public int[] dimSizes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public uint[] elt;
}
Basically function return Uint32Array struct, which represents array of uint elements. In Uint32Array, dimSizes is array length (dimSizes elements need to be multiplied to receive size) and elt is the first element of the array. That means, this uint array can have dynamic length.
Now my usage:
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length);
unsafe public static void ShowAllCharacters()
{
IntPtr ptr = IntPtr.Zero;
OCRPinvoke.ShowAllCharacters(ref ptr);
IntPtr imgPP = (IntPtr)Marshal.PtrToStructure(ptr, typeof(IntPtr));
Uint32Array img = (Uint32Array)Marshal.PtrToStructure(imgPP, typeof(Uint32Array));
uint[] dest = new uint[img.dimSizes[1] * img.dimSizes[0]];
fixed (uint* arrPtr = img.elt)
{
fixed (uint* destPtr = dest)
{
CopyMemory((IntPtr)destPtr, (IntPtr)arrPtr, (uint)dest.Length * sizeof(uint)); // Access violation reading location
}
}
}
My assumption is that this error is due to memory override before i'm able to copy uint array to managed array. Why? I know by fact that in some conditions, size of 'elt' array should be 5038848. If i'm setting SizeConst of the elt variable to 5038848, CopyMemory pass without exception
internal struct Uint32Array
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public int[] dimSizes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5038848)]
public uint[] elt;
}
I have also try to copy array by iterating through loop. Every time, accessing elt elements by index crashes on different index.
My question is if there is any way to lock some range of memory until i copy my array and then release it to being override by other processes?
I was able to solve this problem, inspired by #David Heffernan. He ask why marshaling manually?
Knowing that Uint32Array is sequential, we can read every value directly from pointers and then use Marshal.Copy to receive final managed array:
IntPtr ptr = IntPtr.Zero;
OCRPinvoke.ShowAllCharacters(ref ptr);
imagePtr = Marshal.ReadIntPtr(ptr);
int height = Marshal.ReadInt32(ptr);
int width = Marshal.ReadInt32(ptr + sizeof(int));
int[] img = new int[width * height];
Marshal.Copy(ptr + sizeof(int) * 2, img, 0, img.Length);

Call Delphi DLL Function from C# Question on the Marshalling of Data Type (array of char / array of integer)

Call Delphi DLL Function from C#
Marshalling of Data Type (array of char / array of integer)
delphi function
type
_InputPW = array[0..39] of char;
_InputPW_Len = array[0..1] of integer;
_OutPW = array[0..64] of char;
_OutPW_Len = array[0..1] of integer;
function call_encrypt_pw(Const m_InputPW : _InputPW;
Const m_InputPW_Len : _InputPW_Len;
Const m_ResultPW : _OutPW;
Const m_ResultPW_Len : _OutPW_Len
):integer;stdcall;
external 'Ext.dll' name 'call_encrypt_pw';
C# Code
[DllImport(#"Ext.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.I4)]
public static extern int call_encrypt_pw(
[MarshalAs(UnmanagedType.LPStr, SizeConst = 40)] string input, [MarshalAs(UnmanagedType.LPArray, SizeConst = 2)] int[] input_len, [MarshalAs(UnmanagedType.LPStr, SizeConst = 65)] out string output, [MarshalAs(UnmanagedType.LPArray, SizeConst = 2)] out int[] output_len
);
output / output_len
null return.
I think it's the Marshalling problem.
Please advise me how to modify the code.

How to pass struct with unsigned char* from C# to C++?

I have some C++ dll with struct description and some methods:
struct MSG_STRUCT {
unsigned long dataSize;
unsigned char* data;
}
And function for example:
unsigned long ReadMsg( unsigned long msgId, MSG_STRUCT* readMsg)
{
readMsg->dataSize = someDataSize;
readMsg->data = someData;
}
So I want to call this function from C#:
[StructLayout(LayoutKind.Sequential)]
struct MSG_STRUCT
{
UInt32 dataSize;
byte[] data;
}
[DllImport("mydll.dll")]
public static Int32 ReadMsg( UInt32 msgId, ref MSG_STRUCT readMsg);
So I tried to call C# function like:
var readMsg = new MSG_STRUCT();
readMsg.data = new byte[4128];
Int32 res = ReadMsg( someMsgId, ref readMsg);
But I didn't get smth normal in data.
I also tried to call ReadMsg with IntPrt type parameter, but Marshal.PtrToStructure gave me AccessViolationException sometimes.
I don't have any ideas how to pass a pointer to MSG_STRUCT from C# to C++ and receive the result as filled MSG_STRUCT.data
The final solutionthat worked for me:
I used a part of solution offered by xanatos:
I set CallingConvention = CallingConvention.Cdecl for my DllImport function.
I found out that I also need to change:
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4128)]
public byte[] Data;
Thanks everyone for your help
You could try with:
[StructLayout(LayoutKind.Sequential)]
public struct MSG_STRUCT
{
int dataSize;
IntPtr data;
public byte[] GetData()
{
var bytes = new byte[dataSize];
Marshal.Copy(data, bytes, 0, dataSize);
return bytes;
}
}
[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint ReadMsg(uint msgId, ref MSG_STRUCT readMsg);
and then:
MSG_STRUCT msg = new MSG_STRUCT();
uint res = ReadMsg(123, ref msg);
byte[] bytes = msg.GetData();
Your C function is reassigning the data pointer, so you have to marshal it back to C#. The easiest way (for me) is to simply pass a IntPtr and do some explicit Marshal.Copy(...).
An alternative is to have data a byte[], but then in C-side you have to memcpy(readMsg->data, someData, someDataSize) instead of simply assigning readMsg->data = someData.
Try to change attribute from
[StructLayout(LayoutKind.Sequential)]
to
[StructLayout(LayoutKind.Sequential, Pack=X)]
Where X is 1,2,4,8 ..
Default packing in c++ is 8, so try to set Pack = 8

struct remains unaltered after passing by reference into unmanaged C DLL function

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;
}
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 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.
My C# looks like the following:
[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);
}
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.
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.
The C struct:
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;
};
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;
}
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.
Edit
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;
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;
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
}
and in the C test program:
#include <stddef.h>
//...
int main()
{
size_t len = sizeof(zint_symbol); // 33100
size_t offs = offsetof(zint_symbol, errtxt); // 32984
return 0;
}
Looking at the differences in your P/Invoke declarations, we can see that the successful interface uses the [In, Out] attributes. you should add those to the other function, too.
see here: Are P/Invoke [In, Out] attributes optional for marshaling arrays?
The zint_symbol structure is defined differently in the PDF you linked to. It looks as though you have an incompatibility between your structure and the one the dll version is using.
For instance, in the PDF, scale appears after option_3, whereas you have it before option_1. And the last element in the PDF is bitmap_height, whereas yours continues on after that. There may be other differences, those are just what I noticed.
Although you don't have access to the dll source, in this kind of situation you can test your api by creating a simple dll yourself. Create a simple WinForms solution that has just a form with one button on it, and add a CPP Win32 project to the solution (project type: Win32 Project; application type: DLL). For simplicity, you can just add the struct and a stub function in the existing dllmain.cpp:
struct zint_symbol {
/*
.
.
.
*/
};
extern "C"
{
__declspec(dllexport) int ZBarcode_Encode_and_Print(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle)
{
symbol->bitmap_width = 456;
symbol->errtxt[0] = 'e';
symbol->errtxt[1] = 'r';
symbol->errtxt[2] = 'r';
symbol->errtxt[3] = 0;
return 123;
}
}
And in the WinForms button click event handler etc:
public static void doStuff()
{
zint_symbol symbol = new zint_symbol();
int retval = EncodeAndPrint(ref symbol, "input string", 123, 456);
Console.WriteLine(symbol.bitmap_width);
Console.WriteLine(symbol.errtxt);
}
Set a breakpoint in the dll to set/inspect other values as desired. To do this, you'll need to set "Enable unmanaged code debugging" on your C# project properties debug tab.
Using the above code with the C and C# structures you posted, I found no problems; values I set in the dll were apparent to the C# in the struct.
You can experiment further using this approach, but the bottom line is, you need the right struct definition for the dll version you're using, and currently your struct doesn't match the PDF you linked to. Hopefully you can find the right version of the dll, or the right struct definition for your existing dll.

C# P/Invoke and array of structs containing byte arrays

I need to invoke a native DLL from C# code. As I am not very familiar with C/C++, I can't figure out how a structure defined in C should be declared in C# so it can be invoked. The problem is that two parameters seems to be an array of structs, which I don't know how to declare this in C# (see last code block):
c++ header file:
typedef enum
{
OK = 0,
//others
} RES
typedef struct
{
unsigned char* pData;
unsigned int length;
} Buffer;
RES SendReceive(uint32 deviceIndex
Buffer* pReq,
Buffer* pResp,
unsigned int* pReceivedLen,
unsigned int* pStatus);
c# declaration:
enum
{
OK = 0,
//others
} RES
struct Buffer
{
public uint Length;
public ??? Data; // <-- I guess it's byte[]
}
[DllImport("somemodule.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint SendReceive(
uint hsmIndex,
uint originatorId,
ushort fmNumber,
??? pReq, // <-- should this be ref Buffer[] ?
uint reserved,
??? pResp, // <-- should this be ref Buffer[] ?
ref uint pReceivedLen,
ref uint pFmStatus);
in an equivalent java client, i found that the parameter is not just one Buffer but an array of Buffers. In C# it would look like this:
var pReq = new Buffer[]
{
new Buffer { Data = new byte[] { 1, 0 }, Length = (uint)2 },
new Buffer {Data = requestStream.ToArray(), Length = (uint)requestStream.ToArray().Length },
//according to the header file, the last item must be {NULL, 0}
new Buffer { Data = null, Length = 0 }
};
var pResp = new Buffer[]
{
new Buffer { Data = new byte[0x1000], Length = 0x1000 },
//according to the header file, the last item must be {NULL, 0}
new Buffer { Data = null, Length = 0x0 }
};
This seems strange to me because the extern C method does have a pointer to a Buffer struct (Buffer*) and not a pointer to a Buffer array (Buffer[]*).
How do I need to define the Struct in C# and the parameter types of the extern method?
Any help appreciated, Thanks.
Firstly your struct has the parameters in the wrong order. And the byte array needs to be declared as IntPtr with manual marshalling:
struct Buffer
{
public IntPtr Data;
public uint Length;
}
The p/invoke should be:
[DllImport("MyNativeDll.dll", CallingConvention=CallingConvention.Cdecl)]
static extern RES SendReceive(
uint deviceIndex,
[In] Buffer[] pReq,
[In, Out] Buffer[] pResp,
out uint pReceivedLen,
out uint pStatus
);
The byte array needs to be IntPtr so that the struct is blittable. And that's needed so that the array parameters can be declared as Buffer[].
It's going to be a bit of a pain doing the marshalling of the byte arrays. You'll want to use GCHandle to pin the managed byte arrays, and call AddrOfPinnedObject() to get the address of the pinned array for each struct in your arrays of structs. It will be worth your while writing some helper functions to make that task less painful.
Your method signature in c# should be something like:
[DllImport("MyNativeDll.dll")]
public static extern RES SendReceive (uint32 deviceIndex, ref Buffer pReq, ref Buffer pResp, ref uint pReceivedLen, ref uint pStatus);
See this project, it might hel you in the future so generate native calls from .net
http://clrinterop.codeplex.com/releases/view/14120
Based on the C++ header but without testing, have a look at the following code:
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace WindowsFormsApplication1
{
public class Class1
{
public struct Buffer
{
[MarshalAs(UnmanagedType.LPStr)]
public StringBuilder pData;
public uint length;
}
[DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
static extern int LoadLibrary(string lpLibFileName);
[DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
static extern IntPtr GetProcAddress(int hModule, string lpProcName);
[DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
static extern bool FreeLibrary(int hModule);
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal delegate IntPtr SendReceive(
uint deviceIndex,
ref Buffer pReq,
ref Buffer pResp,
uint pReceivedLen,
uint pStatus);
public void ExecuteExternalDllFunction()
{
int dll = 0;
try
{
dll = LoadLibrary(#"somemodule.dll");
IntPtr address = GetProcAddress(dll, "SendReceive");
uint deviceIndex = 0;
Buffer pReq = new Buffer() { length = 0, pData = new StringBuilder() };
Buffer pResp = new Buffer() { length = 0, pData = new StringBuilder() };
uint pReceivedLen = 0;
uint pStatus = 0;
if (address != IntPtr.Zero)
{
SendReceive sendReceive = (SendReceive)Marshal.GetDelegateForFunctionPointer(address, typeof(SendReceive));
IntPtr ret = sendReceive(deviceIndex, ref pReq, ref pResp, pReceivedLen, pStatus);
}
}
catch (Exception Ex)
{
//handle exception...
}
finally
{
if (dll > 0)
{
FreeLibrary(dll);
}
}
}
}
}

Categories

Resources