本章讲述:C#调用C++封装的dll库函数,以及使用注意事项,分两个章节说明;
注意事项:用 DllImport 属性修饰的方法必须具有 extern 修饰符。
1、使用步骤可分为:C++的dll文件导入、C++的dll函数重写、C#调用C++的函数:
(1)导入库文件:C#中要引用C++的dll,需要使用函数“DllImport”,添加其作用域:using System.Runtime.InteropServices;
DllImport属性应用于方法,要求最少要提供包含入口点的dll的名称。
[DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section,string key,string val,string filePath);
[DllImport("ImageEnhancement.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "ReSize")]
(2)C++的dll函数重写:NewSubSignal--函数名称
[DllImport("skyworth_v6_protocol_dll.dll", EntryPoint = "NewSubSignal", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr NewSubSignal(int Src_Ch, int SubSrc_Num, int src_hstart, int src_vstart, int src_hsize, int src_vsize, string name);
对应C++ 函数(声明和实现)
extern "C" __declspec(dllexport) char * __stdcall NewSubSignal(int Src_Ch, int SubSrc_Num, int src_hstart, int src_vstart, int src_hsize, int src_vsize, char *name);
extern "C" __declspec(dllexport) char * __stdcall NewSubSignal(int Src_Ch, int SubSrc_Num, int src_hstart, int src_vstart, int src_hsize, int src_vsize, char* name)
{
string s(name);
}
(3)C#调用C++函数:调用过后,c++返回Char*数据可以用:(返回指针地址,然后C#中,内存中获取数据)
IntPtr send = NewSubSignal(10, 1, 960, 520, 960, 530, "123ABC小样");
string strtemp = Marshal.PtrToStringAnsi(send);
2、C++参数为结构体时,那么C#也应该定义一个结构体;
(1)C++ 结构体定义
struct A
{
wchar_t osdbuffer[100];
unsigned short ix;
unsigned short iy;
};
被调用函数:
int SetConfig(int type, void *p);
(2)C#结构体定义:注意这里的CharSet,它由c中wchar_t决定的,如果c程序编译时使用Unicode,这里就用CharSet.Unicode,否则使用CharSet.Ansi。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct A
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string osdbuffer;
public ushort ix; //显示坐标x
public ushort iy; //显示坐标y
}
这里有一个很重要的问题,那就是内存在编译时的分配问题。一般默认情况下,内存的分配是4byte的整数倍,在这里我省略了,但为了便于理解,补充一下。结构体A完整一点的定义:(注意Pack的值)
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode,Pack = 4)]
public struct A
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string osdbuffer;
public ushort ix; //显示坐标x
public ushort iy; //显示坐标y
}
(3)C#调用C++函数
A s_a = new A();
int lenght = Marshal.SizeOf(s_a);
IntPtr pA= Marshal.AllocHGlobal(lenght);
Marshal.StructureToPtr(s_a, pA, true);
int type = 1;
int ret = SetConfig( type, pA);
Marshal.FreeHGlobal(pA);//释放