本文通过P/Invoke(Platform Invoke)机制调用DLL中的函数
一、QT DLL接口:
extern "C" Q_DECL_EXPORT bool ProcessData (float *InputData,int Length,Paramter Param, SunShine *RetStructs,int *RetNum)
二、C#调用QT DLL方法:
2.1非托管C++ 的结构体定义如下
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct Paramter
{
[MarshalAs(UnmanagedType.I4)]
public int N;
[MarshalAs(UnmanagedType.R4)]
public float Band;
[MarshalAs(UnmanagedType.I1)]
public bool IsPermit;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SunShine
{
[MarshalAs(UnmanagedType.I4)]
public int Good;
[MarshalAs(UnmanagedType.R4)]
public float Warm;
};
结构体转换工具,下载地址:P/Invoke Interop Assistant工具
结构体转换工具使用方法:P/Invoke Interop Assistant使用简介
2.2 DLLImport的使用
[DllImport("StdCore.dll", EntryPoint = "ProcessData", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern bool ProcessData (float[] Data, int Length, Paramter Param, IntPtr Ptr, ref int Num);
方法被声明为 static,是 P/Invoke 方法所要求的,因为在该 Windows API 中没有一致的实例概念。
被标记为 extern,是提示编译器该方法是通过一个从 DLL 导出的函数实现的,因此不需要提供方法体。
自定义结构数组在C#中使用IntPtr进行封送。
2.3 调用方法
int memSize = Marshal.SizeOf(typeof(SunShine)) * 20;//根据实际情况开辟内存大小
//分配托管类型的内存
IntPtr pt = Marshal.AllocHGlobal(memSize);
//调用非托管类型的API
ProcessData (Data, Length, Param, pt, ref Num);
for (int j = 0; j < Num; j++)
{
MySunShine [j] = (SunShine)Marshal.PtrToStructure((IntPtr)((UInt32)pt + j * Marshal.SizeOf(typeof(SunShine))), typeof(SunShine));
}
//释放内存
Marshal.FreeHGlobal(pt);
通过Marshal.Sizeof(),计算非托管类型所占用的空间,然后通过Marshal.AllocHGlobal()方法从进程的非托管内存中分配内存(字节流),调用非托管类型的API,将API返回数据暂存到前面通过Marshal.AllocHGlobal()方法分配的内存中。最后使用Marshal.FreeHGlobal(), 释放以前从进程的非托管内存中分配的内存。