在实际C#开发项目中,存在如下两种情况
这时候就涉及C#托管代码与C++非托管代码互相调用。
本文介绍C#调用C++的方法以及在C#调用C++产生问题的排查过程和经验总结。
下面介绍C#如何静态和动态调用C++库;
一、C#中静态调用C++动态链接
1. 建立 CppDemo,建立的时候选择DLL动态库。
2. 在DllDemo.cpp文件中添加一个Add函数
extern "C" __declspec(dllexport) int Add(int a,int b)
{
return a+b;
}
3. 编译生成DllDem.dll提供C#使用.
4. 新建C#工程,选择控制台测试程序InteropDemo
5. 在Program.cs中添加引用:using System.Runtime.InteropServices;
6. 在pulic class Program添加如下代码:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace InteropDemo
{
class Program
{
[DllImport("CppDemo.dll", EntryPoint = "Add", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b); //
static void Main(string[] args)
{
Console.WriteLine(Add(1, 2));
Console.Read();
}
}
}
C#中导入C++库并导出需要使用的函数,这样就可以实现C#静态调用C++动态链接库了。。
二、C# 中动态调用C++动态链接
C#除了可以静态调用C++dll以外,通过简单的封装也可以实现C++一样动态加载调用dll的功能,只要封装C++中LoadLibrary, GetProcess, FreeLibrary这几个函数就可以实现动态调用动态链接库。实现过程如下:
1. 将kernel32中的几个方法封装成本地调用类LoadLibraryMethod Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace InteropDemo
{
public static class LoadLibraryMethod
{
[DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
public static extern int LoadLibrary(
[MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);
[DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
public static extern IntPtr GetProcAddress(int hModule,
[MarshalAs(UnmanagedType.LPStr)] string lpProcName);
[DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
public static extern bool FreeLibrary(int hModule);
}
}
2. 使用LoadLibraryMethod类动态加载C++动态链接库,获得函数指针,并且将指针封装成C#中的委托。原因很简单,C#中已经不能使用指针了,如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace InteropDemo
{
class Program
{
static void Main(string[] args)
{
//1. 动态加载C++ Dll
int hModule = LoadLibraryMethod.LoadLibrary(@"c:\CppDemo.dll");
if (hModule == 0) return;
//2. 读取函数指针
IntPtr intPtr = LoadLibraryMethod.GetProcAddress(hModule, "Add");
//3. 将函数指针封装成委托
Add addFunction = (Add)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(Add));
//4. 测试
Console.WriteLine(addFunction(1, 2));
Console.Read();
}
///
/// 函数指针
///
///
///
///
delegate int Add(int a, int b);
}
}
三、 C#调用C++问题排查案例
在实际应用出现一个问题,我们提供一个C++DLL给第三方使用,第三方使用C#调用,C#在调用C++的时候总是崩溃,解决该问题经历了如下排查过程:
四、 注意事项
1. C#调用C++调用约定必须一致,当然C++本身也是一样。
2. C++和c#中对应的数据结构大小一致.
3. c#引用函数的参数类型和c++函数中的参数类型一致。