c# 调用 c++ 的dll
c++ 程序的效率比 c# 的效率高很多
调用包含导出 c 函数的dll
第一步,新建“c++动态链接库”项目
第二步,添加方法
struct KeyItem
{
std::uint32_t x, y, z;
};
extern "C" _declspec(dllexport)
KeyItem FindKey(char* zipFile, char* zipFileName, char* plainFile, char* plainFileName)
{
}
第三步,c#调用
复制 dll 到生成目录
[StructLayout(LayoutKind.Sequential)]
struct KeyItem
{
public uint x, y, z;
}
public static class CrackerDLL
{
[DllImport("cracker.dll", EntryPoint = "FindKey", CallingConvention = CallingConvention.Cdecl)]
internal static extern KeyItem FindKey(string zipFile, string zipFileName, string plainFile, string plainFileName);
}
第四步,使用
注意
生成平台必须选择一样的 x64
或 x86
,不能使用 Any CPU
,否则会报错
调用导出 c++ 函数类的 dll
这种不是专门为跨语言调用生成的dll, 所有的导出函数名都进行了重新命名,不是原始名,因为 c++ 支持函数重载:即同一个函数名可以有不同的参数执行不同的过程
class __declspec(dllexport) MyClass
{
public:
MyClass(int count);
static MyClass* Create(int count);
MyClass Clone() const;
MyClass* Copy();
ColorClass Color;
}
c++ 类的编译规则
其实是分成两部分,一部分是数据(属性都保存在数据里),另一部分方法全都转成了静态方法存在在固定的位置
怎么获取对应函数的名称
最佳方法 ida pro
反编译 dll,然后就是可以在根据函数找到真正的名称
调用类中的静态方法
[DllImport("cracker.dll", EntryPoint = "?Create@MyClass@filename")]
internal static extern nint Create(int count);
类的初始化
[DllImport("cracker.dll", EntryPoint = "??0class@filename")]
internal static extern void Construct(nint handle, int count);
var ptr = Marshal.AllocHGlobal(size); // 创建一个地址分配空间放数据
Construct(ptr, 1); // 初始化
Marshal.FreeHGlobal(ptr); // 记得手动释放
其中 size
是通过 c++ 调用 sizeof(MyClass)
获取的
类属性的赋值和获取值
var handle = ptr; // 类数据的指针
nint colorPtr = handle + colorOffset;
// 就可以通过 colorPtr 获取和设置、调用 ColorClass 的值了
colorOffset
是通过 c++ 调用 &((MyClass*)0)->Color
获取的
特殊的返回值
[DllImport("cracker.dll", EntryPoint = "Clone@class@filename")]
internal static extern nint Clone(nint handle, nint newHandle);
[DllImport("cracker.dll", EntryPoint = "Copy@class@filename")]
internal static extern nint Copy(nint handle);
var ptr = Marshal.AllocHGlobal(size); // 创建一个地址分配空间放数据
Construct(ptr, 1); // 初始化
var ptr2 = Marshal.AllocHGlobal(size); // 创建一个地址分配空间放数据
Construct(ptr2, 1); // 初始化
ptr2 = Clone(ptr, ptr2); // 返回的其实就是 ptr2 的指针
Marshal.FreeHGlobal(ptr2); // 记得手动释放
Marshal.FreeHGlobal(ptr); // 记得手动释放
当 C++ 调用方法返回值有引用和不是引用,
返回引用很好解决 MyClass*
直接写返回指针就行了
但是返回 MyClass const
就是麻烦了
从 ida pro
反编译可以看出实际必须调用前自己手动创建类,再把类的指针进去,当然返回了也是传的那个指针
转载请保留原文链接: https://zodream.cn/blog/id/221.html