一个比较完整的案例 愿与诸君享用 ~
比较有趣的一个梗是 有部分同学你需要知道 当某些大佬在讨论cpp时 他们说的是c++
cpp 是 c++的别名
VS2019 创建C++ DLL 项目
DLL脚本 - 其它 文件不用管
找到 主菜单 - 项目 - 添加类 创建 IUtils类 ( 或者你自己定义的类 它会自动生成.h 和 .cpp 文件 非常的方便 )
IUtils.h 文件: _USRDLL 宏 会在你创建DLL项目的时候自动定义 在普通项目里不存在 这里我们可以用来定义一个宏 区分 dll的导入和导出声明
#pragma once
#ifdef _USRDLL
#define default_dll_api extern "C" _declspec( dllexport )
#else
#define default_dll_api extern "C" _declspec( dllimport )
#endif // _USRDLL
//定义函数指针;
typedef void ( __stdcall* func_void_int )( int N );
/*
*
* dll调用外部方法 输入输出
* example: Unity 调用 c++ dll 回调 Unity
*
* 版权声明:本文为CSDN博主「极客七」的原创文章,遵循CC 4.0 BY - SA版权协议,转载请附上原文出处链接及本声明。
*/
default_dll_api void SetCallback( func_void_int func );
/*
* 返回一个 大于于等于最近就N的2次方数
* int a = get2powHigh(511); //a = 512
*
* 版权声明:本文为CSDN博主「极客七」的原创文章,遵循CC 4.0 BY - SA版权协议,转载请附上原文出处链接及本声明。
* 原文链接:https ://blog.csdn.net/qq_39162566/article/details/113798720
*/
default_dll_api int get2powHigh( int N );
/*
* 返回一个 小于等于最近就N的2次方数
* int a = get2powHigh(511); //a = 256
*
* 版权声明:本文为CSDN博主「极客七」的原创文章,遵循CC 4.0 BY - SA版权协议,转载请附上原文出处链接及本声明。
* 原文链接:https ://blog.csdn.net/qq_39162566/article/details/113798720
*/
default_dll_api int get2powLow( int N );
/*
* 返回一个数的绝对值
*
* 版权声明:本文为CSDN博主「极客七」的原创文章,遵循CC 4.0 BY - SA版权协议,转载请附上原文出处链接及本声明。
* 原文链接:https ://blog.csdn.net/qq_39162566/article/details/113798720
*/
default_dll_api int gk7_abs( int N );
/*
*
* 工具类
*
* 版权声明:本文为CSDN博主「极客七」的原创文章,遵循CC 4.0 BY - SA版权协议,转载请附上原文出处链接及本声明。
* https://blog.csdn.net/qq_39162566
*/
class IUtils {
public:
virtual void destory( ) = 0;
virtual char* version( char* dest ) = 0;
};
default_dll_api IUtils* create( );
IUtils.cpp文件: 需要注意的是 在dll里你任何申请堆的操作 需要额外处理 dll的堆空间和程序运行的堆空间有差异 所以 当你在dll申请一个堆指针的时候 请为此对象在dll域里加上它的释放方法 void release() { delete this; }
#include "pch.h"
#include "IUtils.h"
default_dll_api void SetCallback( func_void_int func )
{
return func( 1 );
}
default_dll_api int get2powHigh( int N )
{
--N;//避免正好输入一个2的次方数
N |= N >> 1;
N |= N >> 2;
N |= N >> 4;
N |= N >> 8;
N |= N >> 16;
return ++N;
}
default_dll_api int get2powLow( int N )
{
return get2powHigh( N ) >> 1;
}
default_dll_api int gk7_abs( int N )
{
return ( N ^ ( N >> 31 ) ) - ( N >> 31 );
}
class Utils: public IUtils {
char _place_hoder[20]; // 大小欺骗法 占位20,防止用户理解
public:
Utils( ) = default;
~Utils( ) = default;
virtual void destory( ) {
delete this;
}
virtual char* version( char* dest ){
strcpy( dest, "1.0.0" );
return dest;
}
};
default_dll_api IUtils* create( )
{
return new Utils;
}
c++ 项目调用
将 输出后的 dll文件及.h头文件 放入一个文件夹 丢入 现在的c++项目里
将 头文件包含引入 并定义函数指针 因为我们的cpp是直接获取函数指针的 放回的是一个void*的指针对象 我们最终需要强转成定义的类型 so. 这时候 .h文件就相当于一个映射模板
#include"lib/IUtils.h"
typedef IUtils* ( *createUtilsFunc )( );
typedef int ( *pABSFunc )( int N );
加载DLL并调用
HINSTANCE hactive = LoadLibrary( L"lib/IUtils.dll" );//加载
if( hactive ) {
pABSFunc p = ( pABSFunc ) GetProcAddress( hactive, "gk7_abs" );
createUtilsFunc p2 = ( createUtilsFunc ) GetProcAddress( hactive, "create" );
int a = p( -16 );
IUtils* b = p2( );
int id = b->ID( );
char version[256];
b->version( version );
FreeLibrary( hactive );//释放
}
输出
Unity项目调用
using System;
using UnityEngine;
public class ReadDLL : MonoBehaviour
{
// Start is called before the first frame update
void Start( )
{
load0( );
}
[DllImport( "IUtils" )]
private static extern int gk7_abs( int N );
delegate void func_void_int( int N );
[DllImport( "IUtils" )]
private static extern int SetCallback( func_void_int result );
delegate int abs( int N );
//动态调用方式
void load0( )
{
Debug.Log( " the '-12' abs : " + gk7_abs( -12 ) );
SetCallback( delegate ( int N )
{
Debug.Log( " result: " + N );
} );
}
}
Unity动态调用c++ DLL的其它奇淫异巧
public class DLLWrapper
{
[DllImport( "kernel32.dll", EntryPoint = "LoadLibrary" )]
public static extern int LoadLibrary(
[MarshalAs( UnmanagedType.LPStr )] string lpLibFileName );
[DllImport( "kernel32.dll", EntryPoint = "GetProcAddress" )]
public static extern IntPtr GetProcAddress( int hModule,
[MarshalAs( UnmanagedType.LPStr )] string lpProcName );
[DllImport( "kernel32.dll", EntryPoint = "FreeLibrary" )]
public static extern bool FreeLibrary( int hModule );
public static T GetDelegateForFunctionPointer<T>( int hModule,
[MarshalAs( UnmanagedType.LPStr )] string lpProcName ) where T:class
{
IntPtr intPtr = DLLWrapper.GetProcAddress( hModule, lpProcName );
return Marshal.GetDelegateForFunctionPointer( intPtr, typeof( T ) ) as T;
}
public static T GetDelegateForFunctionPointer<T>( IntPtr ptr ) where T : class
{
return Marshal.GetDelegateForFunctionPointer( ptr, typeof( T ) ) as T;
}
int i_hand = 0;
public DLLWrapper(string dllpath )
{
i_hand = LoadLibrary( dllpath );
}
~DLLWrapper( )
{
if ( i_hand != 0 )
FreeLibrary( i_hand );
}
public T GetDelegateForFunctionPointer<T>( [MarshalAs( UnmanagedType.LPStr )] string lpProcName ) where T : class
{
return GetDelegateForFunctionPointer<T>( i_hand, lpProcName );
}
}
疑难杂症
主菜单 调试- IUtils调试属性 ( 如果你的DLL项目名是 test 那么就是 test调试属性 ) - C/C++ - 预处理器 - 预处理器定义 - 新增 _CRT_SECURE_NO_WARNINGS
Unity 加载dll 显示报错
确认你的dll 生成是x64的 这点很重要