c# - 如何修复“无法封送“返回值”:托管/非托管类型组合无效(Int/UInt 必须与 SysInt 或 SysUInt 配对)。
问题描述
我试图从 C# 的 C++ 回调中返回一个结构,但我得到了标题中描述的错误。
我很欣赏有很多信息,但我想包含太多而不是不够。
我尝试将函数作为结构返回,但随后阅读可能更容易将函数作为 IntPtr 返回并使用 Marshal.PtrtoStructure。
我要调用的函数来自不同来源的 .dll,输入为:
C++:
rVDACQ_Connect(int, tVDACQ_CallBackProc, void*, short*, int)
示例 (C++) 代码中的函数返回一个结构 (rACQ_CallBackRec),如下所示:
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)
CALLBACK_Aquisition 为:
extern "C" {
__declspec(dllexport) void _stdcall CALLBACK_Acquisition(tVDACQ_CallBackRec* AR)
{
tVDACQ_CallBackProc test;
((CPreviewDlg*)AR->rUserParam)->My_ACQ_CallBack(AR, test);
}
}
结构体的布局如下:
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#
我在 C# 中创建了回调过程,以及结构和 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);
结构:
[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;
}
打回来:
tVDACQ_CallBackProc callBack =
(AR) =>
{
CALLBACK_Acquisition(AR); //Don't know how necessary this
is
};
函数调用:
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.
如果我可以将它作为 IntPtr 返回,或者更好的是,我在 C# 代码中定义的结构会很棒。
如果您需要更多信息,请告诉我,因为我认为我包括了所有内容。
解决方案
推荐阅读
- ubuntu - Octopus 部署和 Ubuntu 权限
- c++ - 如何在 C++ 中向字符串中添加字符?
- php - 字符串替换 + Camel Case
- hive - Spark SQL 临时视图的最佳实践
- python - Python抛出ValueError:list.remove(x):x不在列表中(不在列表上迭代)
- excel - 识别两列中重复的单元格值,并将单独的相应列数据一起列出
- java - DTS中“-07:00”的语义是什么
- laravel - Laravel 传递参数时返回 404 错误
- excel - 将循环结果复制并粘贴到另一张工作表的列中
- ios - 获取 MPMediaPlaylist 上次修改日期