C# 如何调用非托管dll以使用指针填充C中的结构

C# 如何调用非托管dll以使用指针填充C中的结构,c#,c,dll,marshalling,unmanaged,C#,C,Dll,Marshalling,Unmanaged,我正在尝试使用C来使用非托管第三方dll中的函数从文件中获取数据。该函数将指向结构的指针作为输入,并返回未在下面代码中使用的操作成功的状态标志。第三方供应商提供了以下C代码,说明如何调用dll函数: DllCaller.h 布拉格pack1 结构事件 { int事件类型; 双时间戳; 字符事件_文本[200]; }; typedef枚举状态*\u GetEventListstruct事件*事件列表; _GetEventList GetEventList; DllCaller.c int事件列表;

我正在尝试使用C来使用非托管第三方dll中的函数从文件中获取数据。该函数将指向结构的指针作为输入,并返回未在下面代码中使用的操作成功的状态标志。第三方供应商提供了以下C代码,说明如何调用dll函数:

DllCaller.h

布拉格pack1 结构事件 { int事件类型; 双时间戳; 字符事件_文本[200]; }; typedef枚举状态*\u GetEventListstruct事件*事件列表; _GetEventList GetEventList; DllCaller.c

int事件列表; 结构事件*事件列表; hInstLibrary=LoadLibrarylib_名称; GetEventList=\u DWGetEventListGetProcAddresshInstLibrary,GetEventList; printf\n组件:\n; 事件列表=2; 事件列表=mallocsizeofstruct事件*事件列表; GetEventListevent\u列表; fori=0;i<事件列表\u cnt;我++ { PrintFeEvent:类型=%i,文本=%s,位置=%fsec\n, 事件列表[i]。事件类型,事件列表[i]。事件文本, 事件列表[i]。时间戳; } 自由事件列表; 免费图书馆 在示例文件上运行此命令的输出为:

活动:

事件:类型=1,文本=存储已启动,位置=0.000000秒

事件:类型=2,文本=存储停止,位置=110825682秒

换句话说,event_list结构中的每个字段都是长度为2的数组

在上面的代码中,我简化了供应商的示例代码,并省略了一些我认为与当前问题无关的内容

这就是我如何尝试在C中实现相同功能的原因:

[StructLayoutKind.Sequential,Pack=1,CharSet=CharSet.Ansi] 公共结构事件 { [MarshalAsUnmanagedType.ByValArray,ArraySubType=UnmanagedType.I4] 公共int[]事件类型; [MarshalAsUnmanagedType.ByValArray,ArraySubType=UnmanagedType.R8] 公共双[]时间戳; [MarshalAsUnmanagedType.ByValArray,ArraySubType=UnmanagedType.LPStr,SizeConst=200] 公共字符[]事件\文本; } [UnmanagedFunctionPointerCallingConvention.Cdecl] 私有委托状态GetEventListIntPtr ptrToEventList; 公共事件GetEventList { //this.pDll是指向dll库的指针。 IntPtr PaddressOfffunctionToCall=NativeMethods.GetProcAddressthis.pDll,GetEventList; GetEventList GetEventList=GetEventListMarshall.GetDelegateForFunctionPointerAddressOfFunctionToCall,类型为GetEventList; int事件列表计数; this.GetEventListCountout eventListCount,out errorMessage; int mem=Marshal.SizeOftypeofEvent; //2的乘法是因为我已经知道了 //结构应该由两个事件填充。 IntPtr structPtr=Marshal.allocTaskMem2*mem; 事件列表; 尝试 { getEventListstructPtr; eventList=EventMarshall.ptrStructureStructurePtr,事件类型; } 最后 { 费雷赫·洛巴尔斯特普特元帅; } 返回事件列表; } 如果我在与上面的C代码相同的示例文件上运行它,eventList中的事件类型和时间戳向量的长度将为1,事件文本的长度将为200。这些字段中的值将包含由上述C代码打印出的第一个事件(事件类型1)的正确信息。当然,事件列表中应该填充的是包含这两个事件的长度为2的向量,但是我修改代码来实现这一点失败了。上面的代码是我编写的唯一一个填充结构中任何内容的代码。我曾尝试将event_文本字段指定为字符串而不是char,但这只会导致AccessViolationException错误,可能是因为我没有正确实现它

有人能帮我修复上面的代码,以便正确填充事件列表吗

谢谢

/埃尔芬达尔

编辑: 已更新C代码,事件结构已更正,并在将事件[]传递到非托管dll之前尝试在C中分配事件[]:

[StructLayoutKind.Sequential,Pack=1,CharSet=CharSet.Ansi] 公共结构事件 { [MarshalAsUnmanagedType.I4] 公共int事件类型; [MarshalAsUnmanagedType.R8] 公众双时间戳; [MarshalAsUnmanagedType.ByValArray,ArraySubType=UnmanagedType.LPStr,SizeConst=200] 公共字符[]事件\文本; } [UnmanagedFunctionPointerCallingConvention.Cdecl] 私有委托状态GetEventListref事件[]事件列表; 公共事件[]GetEventList { //this.pDll是指向dll库的指针。 IntPtr PaddressOfffunctionToCall=NativeMethods.GetProcAddressthis.pDll,GetEventList; GetEventList GetEventList=GetEventListMarshall.GetDelegateForFunctionPointerAddressOfFunctionToCall,类型为GetEventList; 事件[]事件列表=新事件[2]; getEventListref事件列表; 返回事件列表; } 我不知道上面的代码在你的屏幕上的格式是否和我的缩进和bla一样糟糕
nk新行被省略了,但我一直无法让它看起来更好。

这是最终实现该技巧的代码:

[StructLayoutKind.Sequential,Pack=1,CharSet=CharSet.Ansi] 公共结构事件 { [MarshalAsUnmanagedType.I4] 公共int事件类型; [MarshalAsUnmanagedType.R8] 公众双时间戳; [MarshalAsUnmanagedType.ByValTStr,SizeConst=200] 公共字符串事件\文本; } [UnmanagedFunctionPointerCallingConvention.Cdecl] 私有委托状态GetEventList[out]事件[]事件列表; 公共事件[]GetEventList { //this.pDll是指向dll库的指针。 IntPtr PaddressOfffunctionToCall=NativeMethods.GetProcAddressthis.pDll,GetEventList; GetEventList GetEventList=GetEventListMarshall.GetDelegateForFunctionPointerAddressOfFunctionToCall,类型为GetEventList; 事件[]事件列表=新事件[2]; getEventListeventList; 返回事件列表; }
非常感谢leppie和Panos Rontogianis帮我解决了这个问题

为什么要在C中创建事件类型和时间戳数组?哈!观察得很好,莱皮!这是因为我有时在阅读代码时非常马虎。我的大脑读取了事件列表[i]。事件类型为事件列表。事件类型[i]好的,我修改了代码,使事件类型和时间状态不再是数组。在此之后,我还修改了代码,使eventList是一个Event[],eventList=Event[]marshall.ptrtostructurestructureptr,typeofEvent[];运行此代码会产生MissingMethodException:没有为此对象定义无参数构造函数。有没有想过如何解决这个问题?也许Marshal.PtrToStructure不处理数组类型。试着一个接一个地执行。顺便说一句,从我看到的情况来看,在C中分配事件[]并将其传递给非托管函数会容易得多。我喜欢你的建议,在C中分配事件[]。这是我最初想要做的,但我无法让它工作。这次我也无法让它正常工作。你能帮我吗?我将委托重新定义为私有委托状态GetEventListref Event[]eventList;,然后分配事件[]eventList=新事件[2],后跟getEventListref eventList;我删除了Marshal.allocTaskMem和Marshal.ptrto结构位。这给了一个非常讨厌的fatalexecutionengineer错误。有什么想法吗?