c# 调用 c++ 的dll

Fork Me On Github
zodream 编程技术 C# 2021年09月

c# 调用 c++ 的dll

c++ 程序的效率比 c# 的效率高很多

调用包含导出 c 函数的dll

第一步,新建“c++动态链接库”项目

第二步,添加方法

c++
          
struct KeyItem
{
    std::uint32_t x, y, z;
};

extern "C" _declspec(dllexport) 
KeyItem FindKey(char* zipFile, char* zipFileName, char* plainFile, char* plainFileName)
{

}
12345678910

第三步,c#调用

复制 dll 到生成目录

c#
            
[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);
}
123456789101112

第四步,使用

c#
       

var res = CrackerDLL.FindKey("c.zip", "c.txt", "plain.zip", "plain.txt");

res.x
res.y
res.z
1234567

注意

生成平台必须选择一样的 x64x86,不能使用 Any CPU,否则会报错

调用导出 c++ 函数类的 dll

这种不是专门为跨语言调用生成的dll, 所有的导出函数名都进行了重新命名,不是原始名,因为 c++ 支持函数重载:即同一个函数名可以有不同的参数执行不同的过程

c++
              

class __declspec(dllexport) MyClass
{
    public:
        MyClass(int count);
        static MyClass* Create(int count);

        MyClass Clone() const;
        MyClass* Copy();

        ColorClass Color;
}

1234567891011121314

c++ 类的编译规则

其实是分成两部分,一部分是数据(属性都保存在数据里),另一部分方法全都转成了静态方法存在在固定的位置

怎么获取对应函数的名称

最佳方法 ida pro 反编译 dll,然后就是可以在根据函数找到真正的名称

ida pro.PNG

调用类中的静态方法

c#
  
[DllImport("cracker.dll", EntryPoint = "?Create@MyClass@filename")]
internal static extern nint Create(int count);
12

类的初始化

c#
        
[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);  // 记得手动释放
12345678

其中 size 是通过 c++ 调用 sizeof(MyClass) 获取的

类属性的赋值和获取值

c#
     

var handle = ptr; // 类数据的指针
nint colorPtr = handle + colorOffset; 

// 就可以通过 colorPtr 获取和设置、调用 ColorClass 的值了
12345

colorOffset 是通过 c++ 调用 &((MyClass*)0)->Color 获取的

特殊的返回值

c#
                 
[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);  // 记得手动释放
1234567891011121314151617

当 C++ 调用方法返回值有引用和不是引用,

返回引用很好解决 MyClass* 直接写返回指针就行了

但是返回 MyClass const 就是麻烦了

ida pro 反编译可以看出实际必须调用前自己手动创建类,再把类的指针进去,当然返回了也是传的那个指针

点击查看全文
0 405 0