`

用一个类来封装DLL(SO)的动态调用

阅读更多

 

动态调用DLL技术很常见也没有什么特别困难的,但是我总是感觉写起来很烦,要用typedef定义,加载DLL、查找地址,很烦人,所以我找了一个方式,把DLL动态调用的逻辑都封装成了一个类,使用起来就简单多了。

 

直接动态调用的方法,示例如下:

 

1、预定义

 

typedef LinphoneCore* (*funlinphone_core_new)(const LinphoneCoreVTable *vtable,const char *config_path, const char *factory_config, void* userdata);

 

2、定义函数指针变量

funlinphone_core_new pfn_core_new  ;

 

3、动态加载函数

handle = LoadLibrary( "liblinphone-4.dll");

pfn_core_new = (funlinphone_core_new)GetProcAddress( handle,"linphone_core_new");

 

4、调用

 

pfn_core_new(....);

 

 

 

 

这样调用就完成了,还得负责清理(函数指针指向NULL,卸载DLL等工作)。

 

使用类封装,先要使用下面一个类(添加到工程即可)

 

/****************************************************************************
*                                 DEFINE_PROC
* Inputs:
*       result: The result type; if a linkage type such as WINAPI, CALLBACK,
*        etc. is required, use DEFINE_PROC_LINKAGE
*    name: The function name
*    args: The argument list, enclosed in parentheses
* Notes:
*       There are as many of these as required for your methods to be called
****************************************************************************/

#define DEFINE_PROC(result, name, args) \
    protected: \
        typedef result (*name##_PROC) args; \
    public: \
        name##_PROC name;

/****************************************************************************
*                             DEFINE_PROC_LINKAGE
* Inputs:
*       result: Result type
*    linkage: Linkage type, e.g., CALLBACK, WINAPI
*    name: Function name
*    args: Argument list enclosed in ( )s
* Notes:
*       There are as many of these as required for your methods to be called
****************************************************************************/

#define DEFINE_PROC_LINKAGE(result, linkage, name, args) \
     protected: \
        typedef result (linkage * name##_PROC) args; \
     public: \
    name##_PROC name;

/****************************************************************************
*                               IMPLEMENT_PROC
* Inputs:
*       name: The name of the function, as used as the second argument of
*        DEFINE_PROC.
* Notes:
*       This must appear between a BEGIN_PROC_TABLE and END_PROC_TABLE
****************************************************************************/

#define IMPLEMENT_PROC(name) \
    IMPLEMENT_PROC_SPECIAL(name, #name)

/****************************************************************************
*                           IMPLEMENT_PROC_SPECIAL
* Inputs:
*       name: The name as defined by IMPLEMENT_PROC or IMPLEMENT_PROC_LINKAGE
*    externalname: The external name
* Notes:
*       This must appear between a BEGIN_PROC_TABLE and END_PROC_TABLE
****************************************************************************/

#define IMPLEMENT_PROC_SPECIAL(name, externalname) \
    name = loading ? (name##_PROC)GetProcAddress(library, externalname) : NULL; \
    { \
     DWORD err = ::GetLastError(); \
     if(loading) \
    ASSERT(name != NULL); \
     if(loading && name == NULL) \
       { \
    ::SetLastError(err); \
       } \
    }

/****************************************************************************
*                              BEGIN_PROC_TABLE
*                END_PROC_TABLE
* Effect:
*       This declares the method that initializes the method pointers.
*    There can be only one BEGIN_PROC_TABLE declaration per class.
*    Following this are some number of IMPLEMENT_PROC lines,
*    followed by END_PROC_TABLE
****************************************************************************/

#define BEGIN_PROC_TABLE() protected: virtual BOOL Define(BOOL loading) { ::SetLastError(ERROR_SUCCESS);
#define END_PROC_TABLE()   return TRUE; }

/****************************************************************************
*                              DECLARE_PROC_DLL
* Inputs:
*       myclass: The name of your subclass. This must be the same as
*          the class name you used to declare the class
*    superclass: This allows you to derive additional subclasses;
*        normally you will use the DynamicDLL class here
* Effect:
*       Defines the constructors and destructors for the subclass
****************************************************************************/

#define DECLARE_PROC_DLL(myclass, superclass) \
   public: \
       myclass() : superclass() {} \
       myclass(LPCTSTR module) : superclass(module) { Load(module); } \
       virtual ~myclass() { Free(); }
                     

/****************************************************************************
*                                 DynamicDLL
*       This is the abstract superclass on which all other classes are based
*    It defines the basic behavior of the class.
****************************************************************************/

class DynamicDLL {
    public:
       DynamicDLL() { Init(); }
       DynamicDLL(LPCTSTR name) { Init(); }
       virtual ~DynamicDLL() { }
       BOOL Load(LPCTSTR name) { ::SetLastError(ERROR_SUCCESS);
                 ASSERT(library == NULL); // Attempt to load twice?
                 if(library != NULL)
                    { /* already loaded */
                     //::SetLastError(ERROR_INVALID_HANDLE);
                     return FALSE;
                    } /* already loaded */
                                 library = ::LoadLibrary(name);
                 if(library != NULL)
                    return Define(TRUE);
                 Free();
                 return FALSE;
       }
       void Free() {if(library != NULL)
                   ::FreeLibrary(library);
                    library = NULL;
            Define(FALSE); }
       BOOL IsLoaded() { return library != NULL; }
    protected:
       void Init( ) { library = NULL; }
       HINSTANCE library;
       virtual BOOL Define(BOOL loading) { ASSERT(FALSE); return FALSE; } // must define in subclass
                          // Did you forget to do a BEGIN_PROC_TABLE?
};

/****************************************************************************
*                                   Example
****************************************************************************/
//class TestDynDLL: public DynamicDLL {
//   DECLARE_PROC_DLL(TestDynDLL, DynamicDLL)
//
//     DEFINE_PROC(LRESULT, Test, (LPCTSTR, int))
//     DEFINE_PROC_LINKAGE(BOOL, WINAPI, Test2, ( ) )
//
//     BEGIN_PROC_TABLE()
//         IMPLEMENT_PROC(Test)
//         IMPLEMENT_PROC_SPECIAL(Test2, "_Test2@0")
//     END_PROC_TABLE()
//
//};

 

有了这个类,就可以作为封装DLL调用的基础。

 

示例如下,例如调用windows中,user32.dll中的函数MessageBoxA,步骤如下:

 

首先,建立一个新的类,继承DynamicDLL类,在其中,声明所需使用的函数:

 

#include "DynamicDLL.h"

class TestDynDLL: public DynamicDLL {
    DECLARE_PROC_DLL(TestDynDLL, DynamicDLL)
       
        DEFINE_PROC_LINKAGE(int, WINAPI, MessageBoxA, ( HWND,LPCSTR,LPCSTR,UINT) )
       
        BEGIN_PROC_TABLE()
        IMPLEMENT_PROC(MessageBoxA)

        END_PROC_TABLE()
};

 

 

 

在需要调用的地方,调用上面这个类:

 

    TestDynDLL * DLL;
    DLL = new TestDynDLL(_T("user32.dll"));
    ASSERT(DLL->IsLoaded());
    int rr = DLL->MessageBoxA(this->GetSafeHwnd(),(LPCSTR)"22",(LPCSTR)"dsasdsa",MB_OK);
    delete DLL;

 

 

怎么样,是不是感觉好用多了?我没有在Linux下面测,估计稍加改动,Linux也能使用这种机制。

 

需要注意的是,在继承类中的这个声明,需要仔细写,函数名、参数、返回值、调用约定都需要保持一致,否则会出错的哦。

 

 

 

 

分享到:
评论

相关推荐

    C++调用WebService封装成DLL,供外部调用

    本文将深入探讨如何使用C++调用WebService并封装成动态链接库(DLL),以便其他应用程序能够轻松地调用这些功能。 首先,我们需要理解WebService的基本概念。WebService是一种基于标准的、平台和语言无关的接口,它...

    在C++中将Winsock2进一步封装,导出dll文件,在C#中调用dll

    例如,可以封装一个`Socket`类,包含初始化、连接、发送和接收数据的方法。 - 为了导出这些函数到DLL,需要使用`__declspec(dllexport)`关键字来声明函数。在DLL的头文件中,将这些函数声明为`dllexport`,而在使用...

    C语言实现的动态链接封装实例(包含linux系统和windos系统的两个例子/dll库封装/so库封装)

    动态链接库(Dynamic Link Library, DLL)是Windows操作系统中的一个概念,而共享对象库(Shared Object, SO)则是Linux系统下的等价物。本篇将详细介绍C语言在Windows和Linux系统下如何实现动态链接库的封装以及如何...

    科大讯飞语音合成示例(离线版本) java可调用 dll so封装

    提供java jni示例程序,linux so工程,windows dll工程,将科大讯飞语音合成程序封装成windows支持的dll和linux支持的so并且导出api,java使用jni直接调用。代码均已编译测试通过,需要appid和mscdll则可以自己去...

    c#调用c++ dll 传参 string 崩溃的一种解决办法

    一个常见的场景是C#调用C++编写的动态链接库(DLL)。然而,在这种情况下可能会遇到一些问题,比如当向C++ DLL传递字符串参数时程序崩溃的情况。本文将详细探讨这一问题,并提供一种可能的解决方案。 #### 问题背景...

    使用JNA替代JNI调用DLL,并解决内存溢出问题

    为了解决上述问题,一种常见的策略是请求C++团队编写一个DLL文件来负责解析二进制数据,然后Java应用通过调用该DLL来获取解析后的结果,通常是以JSON格式返回。这就涉及到如何在Java中调用DLL的问题。 #### 方案...

    yolov3 dll c# 调用

    5. **创建C#接口**:在C#项目中,创建一个类来封装DLL的调用,定义DllImport属性以指定DLL中的函数。这些函数可能包括初始化模型、进行推理和释放资源等。 6. **调用DLL**:在C#代码中,实例化上述类,然后调用其...

    通过JNI调用第三方动态库(生成两个.so文件)

    为了编译生成.so文件,我们需要一个Makefile来指导NDK如何处理源代码。以下是一个简单的Makefile示例: ```makefile LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := add LOCAL_SRC_FILES :...

    在Java程序中使用JNative调用dll文件

    在Java程序中调用DLL(动态链接库)文件通常是通过JNI(Java Native Interface)来实现的,而JNative是JNI的一个封装库,它提供了一种更简洁的方式来调用C/C++编写的本地代码。这篇博客文章可能介绍了如何利用...

    delphi编写so库,及调用实例,linux下运行,Deepin系统

    在Delphi中,我们可以使用`library`关键字来定义一个共享库。在library块内,声明公共函数和类型,这些将在其他应用程序中使用。例如: ```delphi library MyLib; uses System.SysUtils; exports MyFunction ...

    CVI调用DLL

    DLL(Dynamic Link Library)是Windows操作系统中的一个核心组件,它封装了一系列可重用的功能,允许不同程序共享代码和资源,提高效率。当我们谈论"CVI调用DLL"时,我们关注的是如何在CVI环境中使用DLL文件来扩展或...

    最简单的JNA调用DLL

    创建一个Java接口,声明你打算调用的DLL函数。接口中的方法必须使用`native`关键字,并且不提供实现。例如,如果你有一个名为`MyDllFunction`的函数,其原型为`int MyDllFunction(int param)`,则接口定义如下: `...

    Qt封装带界面的纯虚类动态库

    在本文中,我们将深入探讨如何使用Qt框架封装一个带界面的纯虚类动态库。Qt是一个流行的开源跨平台应用程序开发框架,广泛应用于GUI(图形用户界面)开发。它提供了丰富的类库,支持C++编程,并且可以运行在多种操作...

    java调用c++生成so库

    标题“java调用c++生成so库”指的是在Linux环境下,通过JNI技术,Java程序可以调用预先用C++编译生成的动态链接库(.so文件)。.so文件是Linux下的动态共享对象,相当于Windows下的.DLL文件,它包含了可由多个程序...

    C++库封装JNI接口-实现java调用c++

    4. **编译C++代码**:将C++源代码编译为动态链接库(在Windows上是.dll,在Linux上是.so,在macOS上是.dylib)。确保正确链接了JNI库。 5. **加载库**:在Java中,`System.loadLibrary()`会加载前面创建的动态链接...

    动态调用库函数支持库

    在Windows系统中,动态调用库函数通常涉及到DLL(Dynamic Link Library)文件,而在Unix/Linux环境中,我们则使用共享对象库(.so文件)。动态调用库函数的一个主要优点是能够减少内存占用,因为多个程序可以共享...

    Redis封装动态库

    在IT行业中,为了方便开发和集成,经常会将Redis的操作接口封装成一个动态库,便于其他应用程序调用。本篇文章将深入探讨Redis封装动态库的相关知识点。 一、Redis动态库的构建 1. 封装接口:首先,我们需要识别...

    [JAVA]使用JNI技术实现JAVA程序调用dll

    在 Java 程序中,我们可以使用 native 定义一个方法来调用这个 dll 文件: public native int readData(int icdev, int offset, int len, byte[] dataBuffer ); 然后,我们可以使用 JNI 来加载这个 dll 文件,并在...

    百度人脸识别离线SDKV1.1版封装动态库供C#调用

    资料; 非常感谢,如有侵权,请与本人联系;...本demo的BaiduFaceDll\BaiduFaceDll目录,是本封装dll的c++源码。VS版本为2015,Framework版本为4.0。 本DEMO只是封装了几个示例,其余封装,参考样式自行编写;

    jnative调用动态库

    标题中的“jnative调用动态库”指的是Java中使用JNative库来调用本地(操作系统级别的)动态链接库(DLL或SO文件)的技术。在Java中,为了与操作系统底层功能进行交互,比如调用C/C++编译的库,我们可以使用Java ...

Global site tag (gtag.js) - Google Analytics