C# 与 C++ 互操作(C# 调用 C++ 的动态链接库)
1.新建 C++ 动态链接库项目
CPlus.cpp:
#include "stdafx.h" extern "C" __declspec(dllexport) void HelloWorld(char* name) { name[0] = 'c'; }
stdafx.h:
#pragma once #include "targetver.h" #define WIN32_LEAN_AND_MEAN #includeextern "C" __declspec(dllexport) void HelloWorld(char* name);
编译 C++ 项目得到 DLL
2.新建 C# 项目
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace CSharp { class Program { [DllImport("kernel32.dll", CharSet = CharSet.Ansi)] static extern IntPtr LoadLibrary(string lpFileName); //加载动态链接库 [DllImport("kernel32.dll", CharSet = CharSet.Ansi)] static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); //获取接口地址 [DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true, CharSet = CharSet.Ansi)] static extern bool FreeLibrary(IntPtr hModule); private delegate void DelegateHelloWorld(IntPtr a); private static void Main(string[] args) { IntPtr hModule = LoadLibrary(@"D:\MyProject\CSharp\CSharp\bin\Debug\Cplus.dll"); IntPtr proc = GetProcAddress(hModule, "HelloWorld"); Byte[] array = new Byte[100]; array[0] = (byte)'a'; array[1] = (byte)'b'; array[2] = (byte)'c'; IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(array, 0); DelegateHelloWorld delegate1 = Marshal.GetDelegateForFunctionPointer(proc, typeof(DelegateHelloWorld)) as DelegateHelloWorld; delegate1(ptr); string str = Encoding.ASCII.GetString(array).Replace("\0", ""); Console.WriteLine(str); Console.ReadLine(); } } }
总体效果是 C# 传入 abc 字符串,C++ 的方法将第一个字节改为 c,C# 得到 cbc。
不同语言之间互相调用需要注意各种数据类型的长度问题,还有编译时选择 32 位 , 64 位的问题。所以使用 数组进行数据交换是比较好的做法。
在将数组转换为字符串时要注意编码格式,常见的是 ASCII, ANSI, UTF8等。