首先包一个C++的DLL
#pragma once
//求和
extern "C" __declspec(dllexport) int Add(int &a,int &b);
//求和1
extern "C" __declspec(dllexport) int Add1(int a, int b);
#include "MyDLL.h"
using namespace std;
//求和
int Add(int &a,int &b)
{
return a+b;
}
//求和1
int Add1(int a, int b)
{
return a + b;
}
然后编译生成得到一个MyDLL.dll文件
C++代码调用
#include <iostream>
#include <Windows.h>
#include <string>
using std::string;
using std::cin;
using std::cout;
using std::endl;
LPCWSTR StringToLPCWSTR(string orig);
int main()
{
//申明
typedef int(*Add)(int &a,int &b);
//加载程序集
HMODULE hDllmy = LoadLibraryW(StringToLPCWSTR("MyDLL.dll"));
//获得错误
auto err1 = GetLastError();
if (hDllmy != NULL)
{
//得到方法
Add AddHandle = (Add)GetProcAddress(hDllmy, "Add");
if (AddHandle != NULL)
{
int a = 1;
int b = 1;
//执行
int he = AddHandle(a, b);
cout << "和:" << he << endl;
}
FreeLibrary(hDllmy);
}
/*typedef string(*ReadMagCard)(string type);
HMODULE hDll = LoadLibraryW(StringToLPCWSTR("WQReadPersonInfo.dll"));
if (hDll != NULL)
{
auto aa= GetProcAddress(hDll, "ReadMagCard");
auto err=GetLastError();
ReadMagCard ReadHandle = (ReadMagCard)GetProcAddress(hDll, "ReadMagCard");
if (ReadHandle != NULL)
{
cout<< "读到卡号:"<<ReadHandle("RType")<< endl;
}
FreeLibrary(hDll);
}*/
string in;
cin >> in;
return 0;
}
//String转LPCWSTR
LPCWSTR StringToLPCWSTR(string orig)
{
size_t origsize = orig.length() + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t* wcstring = (wchar_t*)malloc(sizeof(wchar_t) * (orig.length() - 1));
mbstowcs_s(&convertedChars, wcstring, origsize, orig.c_str(), _TRUNCATE);
return wcstring;
}
效果
如果加载程序集和方法不成功可以用depends.exe查看动态库的依赖,然后补全依赖就行
C#代码调用
/// <summary>
/// 测试C++
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnTestC_Click(object sender, EventArgs e)
{
object[] para = new object[2];
int a =1;
int b =1;
para[0] = a;
para[1] = b;
object ret = InvokeDllUtil.CommonDllInvoke(Application.StartupPath + "\\MyDLL.dll", "Add1", para, typeof(int));
MessageBox.Show(ret.ToString());
}
用反射发出动态构造C#调用方法代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Windows.Forms;
namespace DllInvokTest
{
///<summary NoteObject="Class">
/// [功能描述:动态调用dll的工具类] <para/>
/// [创建者:zlz] <para/>
/// [创建时间:2020年5月12日] <para/>
///<说明>
/// [说明:动态调用dll的工具类]<para/>
///</说明>
///<修改记录>
/// [修改时间:本次修改时间]<para/>
/// [修改内容:本次修改内容]<para/>
///</修改记录>
///<修改记录>
/// [修改时间:本次修改时间]<para/>
/// [修改内容:本次修改内容]<para/>
///</修改记录>
///</summary>
public class InvokeDllUtil
{
/// <summary>
/// 加载程序集
/// </summary>
/// <param name="lpLibFileName"></param>
/// <returns></returns>
[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern long GetLastError();
/// <summary>
/// 加载程序集
/// </summary>
/// <param name="lpLibFileName"></param>
/// <returns></returns>
[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern IntPtr LoadLibrary(string lpLibFileName);
/// <summary>
/// 得到方法地址
/// </summary>
/// <param name="hModule"></param>
/// <param name="lpProcName"></param>
/// <returns></returns>
[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
/// <summary>
/// 释放程序集
/// </summary>
/// <param name="hLibModule"></param>
/// <returns></returns>
[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern IntPtr FreeLibrary(IntPtr hLibModule);
/// <summary>
/// 动态调用Windows DLL
/// </summary>
/// <param name="fileName">Dll文件名</param>
/// <param name="funName">待调用的函数名</param>
/// <param name="objParams">函数参数</param>
/// <param name="returnType">返回值</param>
/// <returns>调用结果</returns>
public static object CommonDllInvoke(string fileName, string funName, object[] objParams, Type returnType)
{
IntPtr libHandle = IntPtr.Zero;
try
{
//获取函数地址
libHandle = LoadLibrary(fileName);
if (libHandle == IntPtr.Zero)
{
long err=GetLastError();
return null;
}
IntPtr procAddres = GetProcAddress(libHandle, funName);
if (procAddres == IntPtr.Zero)
{
return null;
}
//获取参数类型
Type[] paramTypes = new Type[objParams.Length];
for (int i = 0; i < objParams.Length; ++i)
{
paramTypes[i] = objParams[i].GetType();
}
//构建调用方法模型
AssemblyName asembyName = new AssemblyName();
asembyName.Name = "WinDllInvoke_Assembly";
AssemblyBuilder asembyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asembyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = asembyBuilder.DefineDynamicModule("WinDllInvoke");
MethodBuilder methodBuilder = moduleBuilder.DefineGlobalMethod("InvokeFun", MethodAttributes.Public | MethodAttributes.Static, returnType, paramTypes);
//获取一个 ILGenerator ,用于发送所需的 IL
ILGenerator IL = methodBuilder.GetILGenerator();
for (int j = 0; j < paramTypes.Length; ++j)
{
//将参数压入堆栈
if (paramTypes[j].IsValueType)
{
//By Value
IL.Emit(OpCodes.Ldarg, j);
}
else
{
//By Addrsss
IL.Emit(OpCodes.Ldarga, j);
}
}
// 判断处理器类型
if (IntPtr.Size == 4)
{
IL.Emit(OpCodes.Ldc_I4, procAddres.ToInt32());
}
else if (IntPtr.Size == 8)
{
IL.Emit(OpCodes.Ldc_I8, procAddres.ToInt64());
}
else
{
throw new PlatformNotSupportedException("不支持的处理器类型!");
}
IL.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, returnType, paramTypes);
// 返回值
IL.Emit(OpCodes.Ret);
moduleBuilder.CreateGlobalFunctions();
// 取得方法信息
MethodInfo methodInfo = moduleBuilder.GetMethod("InvokeFun");
object retObj= methodInfo.Invoke(null, objParams);
// 调用方法,并返回其值
return retObj;
}
catch
{
return null;
}
finally
{
if (libHandle != IntPtr.Zero)
{
//释放资源
FreeLibrary(libHandle);
}
}
}
}
}
效果
参数带引用的一直返回的结果不对,还得再学习啊。用C++直接调用更接近,用C#调用经过了P/Invoke后有的时候莫名其名调用效果不对很费劲。