C# 调用C++封装的dll库函数的方法(一)

本章讲述: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);//释放

猜你喜欢

转载自blog.csdn.net/BYH371256/article/details/120413748