编写C++非托管DLL以及在.NET托管中调用
新建项目,来到Win32,点击Win32项目
输入名称MyVC点击确定。
应用程序类型,勾选DLL,点击完成。
MyVC.cpp
#include "stdafx.h"
#include
extern "C" __declspec(dllexport) int Max(int a,int b)
{
return a>b?a:b;
}
extern "C" __declspec(dllexport) int Min(int a,int b)
{
return a>b?b:a;
}
//此示例来自CSDN
extern "C" __declspec(dllexport) void GetName(char* buffer, int* size)
{
printf("before copy the length is:%d\n", *size);//写数据前buffer的容量
char temp[] = "hello,world";
strcpy(buffer,temp); //模拟写数据
printf("OK, string is:%s\n", buffer);
*size = (int)strlen(temp);
printf("after copy the length is:%d\n", *size);//写数据后buffer的容量
}
其中 extern "C " 生成的dll,不会分解函数名
其中 __declspec(dllexport) 导出dll为其他程序调用
好了,生成即可。
生成的dll放到 C:\WINDOWS\system32 目录下面,这样不需要指定路径。
或者不放在此文件夹下面,那直接指定完整的目录也可以。
嗯,现在在.NET中调用它
using System.Runtime.InteropServices;
[DllImport(@"D:\MyVC\Debug\MyVC.dll")]
public extern static void GetName(StringBuilder sb, IntPtr length);
[DllImport(@"D:\MyVC\Debug\MyVC.dll")]
public extern static int Max(int a, int b);
[DllImport(@"D:\MyVC\Debug\MyVC.dll")]
public extern static int Min(int a, int b);
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder(256);
IntPtr ptr = Marshal.AllocHGlobal(sizeof(int));//申请一个整数指针
Marshal.WriteInt32(ptr, sb.Capacity);//给指针内容赋初值为缓冲区容量
GetName(sb, ptr);
Marshal.FreeHGlobal(ptr);
Console.WriteLine(Max(22, 106).ToString()); //106
Console.WriteLine(Min(22, 106).ToString()); //22
Console.Read();
}
我在制作过程中遇到的一些问题:
无法加载 DLL“MyVC.dll”: 参数不正确。 (异常来自 HRESULT:0x80070057 (E_INVALIDARG))。
清理解决方案再生成
对 PInvoke 函数“ConsoleApplication1!ConsoleApplication1.Program::Max”的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配。
点击C++项目属性,来到配置属性下面的C/C++,点击高级
在右边的“调用约定”里,选择__stdcall (/Gz)