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);
Related
How would you marshall this nested array of structure in C#?
C struct:
typedef struct
{
unsigned int appVersionNumber;
unsigned int networkId;
struct
{
int code;
int endDate;
} profiles[4];
} CardEnvHolder;
My C# attempt:
[StructLayout(LayoutKind.Sequential)]
unsafe struct CardEnvHolder
{
public uint appVersionNumber;
public uint networkId;
public Profiles[] profiles;
}
[StructLayout(LayoutKind.Sequential)]
struct Profiles
{
public int code;
public int endDate;
}
C# Main:
unsafe
{
CardEnvHolder envhold = new CardEnvHolder();
void* ptr = (void*)&envhold; //Error here
EnvHolderTest(ptr);
Console.WriteLine(envhold.profil[1].code);
}
Unfortunately I get the error CS0208 "Cannot take the address of, get the size of, or declare a pointer to a managed type ('T')"
As requested,
EnvHolder C function:
void EnvHoldInit(CardEnvHolder* envhold)
{
envhold->appVersionNumber = 4;
envhold->networkId = 8;
envhold->profiles[1].code = 84;
printf("%d\n", envhold->profiles[1].code);
envhold->profiles[1].code++;
}
EXPORT void EnvHolderTest(void* envhold)
{
EnvHoldInit(envhold);
}
EnvHolder C# prototype:
[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl)]
extern static unsafe void EnvHolderTest([In, Out] void* envhold);
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.
The Sctruct
I am not much of a C# or C programmer and have not found much guidance on specifying pointers and structs within a struct. I am attempting to import the following from a C dll into a C# program:
#define MAXFILENAME 259
struct IDentry {
char* IDname;
int length;
};
typedef struct IDentry idEntry;
struct SMOutputAPI {
char name[MAXFILENAME + 1];
FILE* file;
struct IDentry *elementNames;
long Nperiods;
int FlowUnits;
int Nsubcatch;
int Nnodes;
int Nlinks;
int Npolluts;
int SubcatchVars;
int NodeVars;
int LinkVars;
int SysVars;
double StartDate;
int ReportStep;
__int64 IDPos;
__int64 ObjPropPos;
__int64 ResultsPos;
__int64 BytesPerPeriod;
};
I am not sure how to handle the *elementsNames, file or name properties. What I have so far in C# is:
int MAXFILENAME = 259
[StructLayout(LayoutKind.Sequential)]
public struct SMOutputAPI
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXFILENAME+1)]
public string name;
IntPtr file;
IntPtr elementNames;
public long Nperiods;
public int FlowUnits;
public int Nsubcatch;
public int Nnodes;
public int Nlinks;
public int Npolluts;
public int SubcatchVars;
public int NodeVars;
public int LinkVars;
public int SysVars;
public double StartDate;
public int ReportStep;
public int IDPos;
public int ObjPropPos;
public int ResultsPos;
public int BytesPerPeriod;
};
The C# application builds fine, but when I call the C initialization function that should return a new SMOutputAPI struct I get an error:
System.Runtime.InteropServices.MarshalDirectiveException
Method's type signature is not PInvoke compatible.
Any thoughts on how to properly specify this struct in C# would be much appreciated. Thanks!
Initializing the Struct
The struct is initialized in the c-code with:
SMOutputAPI* DLLEXPORT SMO_init(void)
//
// Purpose: Returns an initialized pointer for the opaque SMOutputAPI
// structure.
//
{
SMOutputAPI *smoapi = malloc(sizeof(struct SMOutputAPI));
smoapi->elementNames = NULL;
return smoapi;
}
The corresponding c# code is:
[DllImport("swmm-output.dll")]
static extern SMOutputAPI SMO_init();
static void Main(string[] args)
{
Console.Write("Hello World!");
SMOutputAPI SMO = SMO_init();
}
I have three C++ structures that I need to send as parameters when calling a DLL method from C#.
I simplified them as the following:
typedef struct
{
int data1;
int data2;
} A;
typedef struct
{
int numStructA;
A *pStructA;
int moreData;
} B;
typedef struct
{
TCHAR *pStr;
B structB;
} C;
The following is the C++ function I need to call from C#:
int func(C *pStructC, int numStructC);
In my C# code, I define the structs as the following:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct A
{
public int data1;
public int data2;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct B
{
public int numStuctA;
public IntPtr structA;
public int moreData;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct C
{
[MarshalAs(UnmanagedType.LPTStr)]
public string Str;
[MarshalAs(UnmanagedType.Struct)]
public B structB;
}
[DllImport("somedll.dll")]
private static extern int func(IntPtr pStructC, int size);
I tried to marshal the nested structures. However, the C++ function does not receive the data correctly. So far only the data that comes before the nested structure is sent correctly to the C++ function.
How can I marshal the nested structures so the C++ method receives the correct data? Thanks in advance.
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