Vistual Studio 2019 C++ DLL 封装 [ 方法,类成员方法 ]

 

一个比较完整的案例 愿与诸君享用 ~


比较有趣的一个梗是 有部分同学你需要知道 当某些大佬在讨论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的 这点很重要

 

 

 

 

 

Guess you like

Origin blog.csdn.net/qq_39162566/article/details/117667153