Invoke C dll functions,structs and callbacks in C# - c#

Below is the header file.can anyone please give a idea to call the callback function below.
//Function Prototype
int PASCAL EXPORT RegisterCallbackFunctions (TCallbacks CallbackFuncs);
//Data Structure
struct TCallbacks
{
LPONUSSDREQUEST m_pOnRequest;
LPONUSSDRESPONSE m_pOnResponse;
};
struct TData
{
DWORD m_dwCmd;
BYTE m_bVersion;
BYTE m_bCodeScheme;
DWORD m_dwErrorCode;
char m_szMsIsdn[15];
}
//Prototypes
typedef int (*LPONUSSDREQUEST) (HANDLE hLoginInstance, HANDLE hDialog, TData data, DWORD *pdwAppParam);
typedef int (*LPONUSSDRESPONSE) (HANDLE hLoginInstance, HANDLE hDialog, char szString [ ], DWORD dwAppParam);
I have already got the hloginInstance and hDialog functions,But I need help in calling the callback function.
regards,
Jeanix

In .NET you could use delegates:
class Program
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int RequestDelegate(
IntPtr hLoginInstance,
IntPtr hDialog,
IntPtr data,
int pdwAppParam);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int ResponseDelegate(
IntPtr hLoginInstance,
IntPtr hDialog,
string szString,
int dwAppParam);
[DllImport("somelib.dll")]
public static extern void RegisterCallbackFunctions(TCallbacks callbacks);
public struct TCallbacks
{
public RequestDelegate m_pOnRequest;
public ResponseDelegate m_pOnResponse;
}
static void Main(string[] args)
{
TCallbacks callbacks;
callbacks.m_pOnRequest =
(hLoginInstance, hDialog, data, pdwAppParam) => 10;
callbacks.m_pOnResponse =
(hLoginInstance, hDialog, szString, dwAppParam) => 20;
RegisterCallbackFunctions(callbacks);
}
}

The Code Doesn't work me, i think there is a problem init.
Error is in this line :-
callbacks.m_pOnRequest = (hLoginInstance, hDialog, data, pdwAppParam) => 10;
thankx,
jeanix

Related

How to fix 'Cannot marshal 'return value': Invalid managed/unmanaged type combination (Int/UInt must be paired with SysInt or SysUInt).'

I'm trying to return a struct from a C++ callback from C# and I get the error as described in the title.
I appreciate there is a lot of information, but I wanted to include too much rather than not enough.
I've tried returning the function as a structure, but then read it may be easier to return the function as an IntPtr and use Marshal.PtrtoStructure.
The function that I want to call is from a .dll that comes from a different source and the input is:
C++:
rVDACQ_Connect(int, tVDACQ_CallBackProc, void*, short*, int)
the function in the sample (C++) code returns a struct (rACQ_CallBackRec) which is as follows:
rACQ_CallBackRec = theApp.m_Intf.rVDACQ_Connect(cVDACQ_FBright, CALLBACK_Acquisition, this, m_FrmBuffer, 0);
//rACQ_CallBackRec is the struct type tVDACQ_CallBackRec (as described below)
With CALLBACK_Aquisition being:
extern "C" {
__declspec(dllexport) void _stdcall CALLBACK_Acquisition(tVDACQ_CallBackRec* AR)
{
tVDACQ_CallBackProc test;
((CPreviewDlg*)AR->rUserParam)->My_ACQ_CallBack(AR, test);
}
}
The layout of the struct is as follows:
typedef struct {
int rFlags, // combination of cVDACQ_Fxxxx
rType, // cVDACQ_ETxxx
rEvent, // cVDACQ_Exxx
rSocket; // 0:no relation to a 'socket'; otherwise socket's ID>0 (event's source ID)
TCHAR rMsg[256]; // message (trace, wrn, err)
int rFrameWidth, // full frame width
rFrameHeight; // full frame height
short* rFrameBuffer; // user supplied frame buffer "AFrameBuffer"
union {
int rCaptureRows; // # of received rows (for single frame acquisition)
int rCaptureFrames; // # of received full frames (for framegrabber)
};
int rCapturePercent; // received data in percents
void* rUserCallBackProc, // user supplied "ACallBackProc"
* rUserParam; // user supplied "AUserParam"
int rAborted; // 1: VDACQ_Abort -1:internally
void* rPacketData; // pointer to received packet; usually it is nil
int rFGControl; // frame-grabber's control flags
} tVDACQ_CallBackRec;
typedef void(_stdcall* tVDACQ_CallBackProc)(tVDACQ_CallBackRec*); //The Callback
C#
I've created the callback procedure in C#, as well as the struct and PInvoke:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void tVDACQ_CallBackProc(tVDACQ_CallBackRec AR);
[DllImport("C:\\Users\\jch\\source\\repos\\FlatPanelSensor\\x64\\Debug\\VADAV_AcqS.dll", EntryPoint = "CALLBACK_Acquisition", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern void CALLBACK_Acquisition(tVDACQ_CallBackRec AR);
[DllImport("C:\\Users\\jch\\source\\repos\\FlatPanelSensor\\FlatPanelSensor\\bin\\Debug\\VADAV_FGM_64.dll", EntryPoint = "VDACQ_Connect", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I4)]
public unsafe static extern IntPtr VDACQ_Connect(int i, [MarshalAs(UnmanagedType.FunctionPtr)] tVDACQ_CallBackProc proc, dynamic n, IntPtr[] buffer, int j);
Struct:
[StructLayout(LayoutKind.Sequential)]
public struct tVDACQ_CallBackRec
{
public int rFlags;
public int rType;
public int rEvent;
public int rSocket;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string rMsg;
public int rFrameWidth;
public int rFrameHeight;
public IntPtr rFrameBuffer;
public int rCaptureRows;
public int rCaptureFrames;
public int rCapturePercent;
public IntPtr rUserCallBackProc;
public IntPtr rUserParam;
public int rAborted;
public IntPtr rPacketData;
public int rFGControl;
}
CallBack:
tVDACQ_CallBackProc callBack =
(AR) =>
{
CALLBACK_Acquisition(AR); //Don't know how necessary this
is
};
Function call:
IntPtr work = VDACQ_Connect(0, callBack, this, m_FrmBuffer, 0);
//I know 'this' isn't defined as a void* in my DLLImport,
//but making it an IntPtr didn't work either so
//the only type I could think of was dynamic.
If I could return this as a IntPtr or, even better, the struct I defined in my C# code that would be great.
If you need anymore information then please let me know, as I think I included everything.

Marshal callback in a struct from C++ to C#

I need to return the necessary information about an object as a struct with callbacks and other data.
This is what it looks like on the C# side:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ChartAddDataCallback(IntPtr data, int size);
[StructLayout(LayoutKind.Sequential)]
public struct ChartAccessors
{
public IntPtr HWnd;
public ChartAddDataCallback addDataCallback;
}
[DllImport("CppPart.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "GetAccessors")]
public static extern ChartAccessors GetAccessors();
The C++ "mirrored" version looks like this:
typedef void(__cdecl *AddDataCallback) (int * data, int size);
struct ChartAccessors
{
HWND m_chartHWnd;
AddDataCallback m_addDataCallback;
};
extern "C" __declspec(dllexport) ChartAccessors GetAccessors();
Usage:
static void Main(string[] args)
{
ChartAccessors accessors = GetAccessors();
}
However, when i start up the program i get the exception "Method's type signature is not PInvoke compatible."
It works if i use any other return type (like int or float) instead of the struct.
Marshal.PtrToStructure was actually solving this issue, as Pavel pointed out.
void RegisterCallbacks(IntPtr callbackPtr)
{
ChartAccessors accessors = (ChartAccessors)Marshal.PtrToStructure(callbackPtr, typeof(ChartAccessors));
// do stuff with the struct
}

Call C method in C# by DllImport - attempt to read or write protected memory

I have a dll - Lib.dll(written in С or C++). I need to call a function:
extern “C” DWORD call_sb_kernel(
DWORD func,
void *in_arg,
void *out_arg);
This description of the parameters:
DWORD func - is a anumber
void *in_arg - pointer to
typedef struct tagInArg{
void *Reserved;
void *in_struct;
} InArg;
void *out_arg pointer to
typedef struct tagOutArg{
DWORD ErrorCode;
DWORD Flags;
void *Reserved;
void *out_struct;
} OutArg;
return result from function.
I call this function at C#
[DllImport(LibPath, CallingConvention = CallingConvention.StdCall)]
private static extern long call_sb_kernel(uint func, [In, Out] InArg inArg, [In, Out] OutArg outArg);
[StructLayout(LayoutKind.Sequential, Size = 128)]
public struct InArg
{
public IntPtr Reserved;
public IntPtr in_struct;
}
[StructLayout(LayoutKind.Sequential, Size = 128)]
public struct OutArg
{
public Int32 ErrorCode;
public Int32 Flags;
public IntPtr Reserved;
public IntPtr out_struct;
}
public void Test()
{
var outArg = new OutArg();
var res = call_sb_kernel_std(0, new InArg(), outArg);
}
I've tried a lot of options. This is the last version.But I get a runtime error - "Attempt to read or write protected memory". How do I call this function?
call_sb_kernel expects two pointers, not structures. Change your definition to ref InArg inArg, out OutArg outArg and use it like call_sb_kernel_std(0, ref inArg, out outArg);.

DllImport signature error

I have an DLL file named WD_SDK.dll (it go with an SDK.h file).
I open the SDK.h and I see:
typedef void (CALLBACK * VideoCaptureCB_Ptr)(PVOID pContext, BYTE * apData[3],
VideoSampleInfo_T * pVSI);
typedef struct _VideoSampleInfo_T
{
ULONG idFormat; //
ULONG lSignalState;
int nLen; // not used for raw video data(e.g. YUV420)
int nWidth;
int nHeight;
int anPitchs[3]; // only used for raw video data(e.g. YUV420)
ULONG dwMicrosecsPerFrame; // 1000*1000/FPS
ULONG field;
int iSerial;
} VideoSampleInfo_T;
WD_RegisterVideoPreviewCB(HANDLE hChannel, PVOID pContext, VideoCaptureCB_Ptr pCB);
I want to call the WD_RegisterVideoPreviewCB in C#. So I use the DllImport to declare it in C#. It look like this:
[DllImport("WD_SDK.dll", EntryPoint = "_WD_RegisterVideoPreviewCB#12", ExactSpelling = true)]
static extern int WD_RegisterVideoPreviewCB(IntPtr hChannel, object pContext, VideoCaptureCB_Ptr pCB);
Then I re-declare the C++ struct and CALLBACK in C# like this:
public delegate void VideoCaptureCB_Ptr(IntPtr pContext, byte[] apData, VideoSampleInfo_T pVSI);
[StructLayout(LayoutKind.Sequential)]
public struct VideoSampleInfo_T
{
public uint idFormat;
public uint lSignalState;
public int nLen; // not used for raw video data(e.g. YUV420)
public int nWidth;
public int nHeight;
public int[] anPitchs; // only used for raw video data(e.g. YUV420)
public uint dwMicrosecsPerFrame; // 1000*1000/FPS
public uint field;
public int iSerial;
}
And one delegate implement
public static void HandleVideoStatic(IntPtr pContext, byte[] apData, VideoSampleInfo_T pVSI)
{
}
When i run my code :
WD_RegisterVideoPreviewCB(m_ahChannels[i], m_aMediaHandler[i], HandleVideoStatic);
THe program show me an error does not match the unmanaged target signature.
I thinks encountered problem with the PVOID pContext, I changed it to object pContext. But I have to pass the m_aMediaHandler[i] (It's an instance of a class not a pointer) to it, the error raised " .."invalid agruments"
P/S: The WD_RegisterVideoPreviewCB call in C++
WD_RegisterVideoPreviewCB(m_ahChannels[i], &m_aMediaHandler[i], HandleVideoStatic);

Invalid Managed/Unmanaged Type Combination With Embedded, Dynamically-Allocated Array

I have a common construct in an unmanaged Win32 C++ DLL:
// FirstElemPtrContainer.h
#include "stdafx.h"
typedef unsigned char elem_type; // a byte
typedef struct FirstElemPtrContainer {
unsigned char num_elems;
void *allocd_ary;
} FirstElemPtrContainer;
The void* in the struct is meant to contain a pointer to the first element of an allocated byte array.
The DLL that uses this definition then exports functions to allocate, populate, and deallocate the struct:
// The exported allocator function.
extern "C" _declspec(dllexport)
FirstElemPtrContainer *BuildStruct(int elem_count)
{
FirstElemPtrContainer *fepc_ptr = new FirstElemPtrContainer;
fepc_ptr->num_elems = elem_count;
elem_type *ary = new elem_type[fepc_ptr->num_elems];
for (int i = 0; i < fepc_ptr->num_elems; i++)
{
ary[i] = ((i + 1) * 5); // multiples of 5
}
fepc_ptr->allocd_ary = ary;
return fepc_ptr;
}
// The exported deallocator function.
extern "C" _declspec(dllexport) void
DestroyStruct(FirstElemPtrContainer *fepc_ptr)
{
delete[] fepc_ptr->allocd_ary;
delete fepc_ptr;
}
These work just fine for a native caller.
In C#, I try to describe this same structure via PInvoke:
[StructLayout(LayoutKind.Sequential)]
public struct FirstElemPtrContainer
{
public byte num_elems;
[MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.U1, SizeConst = 4)]
public IntPtr allocd_ary;
}
... and describe the call interface like so:
public static class Imports
{
[DllImport("MyLib", CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr BuildStruct(int elem_count);
[DllImport("MyLib", CallingConvention = CallingConvention.Winapi)]
public static extern void DestroyStruct(IntPtr fepc_ptr);
}
Now I attempt to call my interface:
class Program
{
const int NUM_ELEMS = 4;
static void Main(string[] args)
{
IntPtr fepc_ptr = Imports.BuildStruct(NUM_ELEMS);
if ( fepc_ptr == IntPtr.Zero )
{
Console.WriteLine("Error getting struct from PInvoke.");
return;
}
FirstElemPtrContainer fepc =
(FirstElemPtrContainer)Marshal.PtrToStructure(fepc_ptr,
typeof(FirstElemPtrContainer));
//...
}
}
The PtrToStructure() call gives the error "Cannot marshal field 'allocd_ary' of type 'MyLibInvoke.FirstElemPtrContainer': Invalid managed/unmanaged type combination (Int/UInt must be paired with SysInt or SysUInt)."
You can see that I've hard-coded a particular number of elements, which we'll assume the caller adheres to. I've also added an ArraySubType clause, though it seems not to make a difference. Why the type mismatch complaint?
Your struct should be declared like this:
[StructLayout(LayoutKind.Sequential)]
public struct FirstElemPtrContainer
{
public byte num_elems;
public IntPtr allocd_ary;
}
it has to be done this way because allocd_ary is a pointer to unmanaged memory and cannot be marshalled by the p/invoke marshaller.
In order to read the contents of allocd_ary you can use Marshal.Copy.
FirstElemPtrContainer fepc = (FirstElemPtrContainer)Marshal.
PtrToStructure(fepc_ptr, typeof(FirstElemPtrContainer));
byte[] ary = new byte[fepc.num_elems];
Marshal.Copy(fepc.allocd_ary, ary, 0, ary.Length);
I suspect that CallingConvention.Winapi is wrong and that you should be using CallingConvention.Cdecl.

Categories

Resources