zoukankan      html  css  js  c++  java
  • 一个简洁通用的调用DLL函数的帮助类

    一个简洁通用的调用DLL函数的帮助类

     本次介绍一种调用dll函数的通用简洁的方法,消除了原来调用方式的重复与繁琐,使得我们调用dll函数的方式更加方便简洁。用过dll的人会发现c++中调用dll中的函数有点繁琐,调用过程是这样的:在加载dll后还要定义一个对应的函数指针类型,再调用GetProcAddress获取函数地址,再转成函数指针,最后调用该函数。下面是调用dll中Max和Get函数的例子。

    复制代码
    void TestDll()
    {
    typedef int(*pMax)(int a,int b);
    typedef int(*pGet)(int a);
    HINSTANCE hMode =LoadLibrary("MyDll.dll");if(hMode==nullptr)
    return;
    
    PMax Max = (PMax)GetProcAddress(hDLL,"Max");
    if(Max==nullptr)
    return;
    
    int ret =Max(5,8); //8
    
    PMin Get = (PMin)GetProcAddress(hDLL,"Get");
    if(Get==nullptr)
    return;
    
    int ret =Get(5); //5
    
    FreeLibrary(hDLL);
    }
    复制代码

      这段代码看起来很繁琐,因为我没每用一个函数就需要先定义一个函数指针,然后再根据名称获取函数地址,最后调用。如果一个dll中有上百个函数的话,这种重复而繁琐的定义会让人吐的。其实获取函数地址和调用函数的过程是重复逻辑,应该消除,我不想每次都定义一个函数指针和调用GetProcAddress,我觉得可以用一种简洁通用的方式去调用dll中的函数。我希望调用dll中的函数就像调用普通的函数一样,即传入一个函数名称和函数的参数就可以实现函数的调用了。就类似于:

    Ret CallDllFunc(const string&funName, T arg)

    如果以这种方式调用的话,我就能避免繁琐的函数指针定义以及反复的调用GetProcAddress了。

    一种可行的解决方案

      如果要按照

    Ret CallDllFunc(const string& funName, T arg)

    这种方式调用的话,首先我要把函数指针转换成一种函数对象或者泛型函数,这里我们可以用std::function去做这个事情,即通过一个函数封装GetProcAddress,这样通过函数名称我就能获取一个泛型函数std::function,我希望这个function是通用的,不论dll中是什么函数都可以转换成这个function, 最后调用这个通用 
    的function就可以了。但是调用这个通用的function还有两个问题需要解决:

    1. 不同函数的不同类型返回值怎么处理,因为函数的返回值可能是某些类型,如何以一种通用的返回值来消除这种不同返回值导致的差异呢?
    2. 函数的入参数目可能任意个数,且类型也不尽相同,如何来消除入参个数和类型的差异呢?

      我们一个个解决问题吧,首先看看如何封装GetProcAddress,将函数指针转换成std::function。通过如下代码就可以了。

    复制代码
    template <typename T>
    std::function<T> GetFunction(const string&funcName)
    {
    FARPROC funAddress = GetProcAddress(m_hMod, funcName.c_str());
    return std::function<T>((T*)(funAddress));
    }
    复制代码

      其中T是std::function的模板参数,即函数类型的签名。如果我们要获取上面例子中,Max和Get函数,则可以这样获取:

    auto fmax = GetFunction<int(int, int)>("Max");
    auto fget = GetFunction<int(int)>("Get");

      这种方式比之之前先定义函数指针再调用GetProcAddress的方式更简洁通用。

      再看看如何解决函数返回值和入参不统一的问题,关于这个问题,其实在前面的博文中就讲到了,不知道的童鞋看这里: 

    (原创)C++11改进我们的程序之简化我们的程序(一)

      是的,还是通过result_of和可变参数模板来搞定。最终的调用函数是这样的:

    template <typename T, typename... Args>
    typename std::result_of<std::function<T>(Args...)>::type ExcecuteFunc(const string& funcName,Args&&... args)
    {
    return GetFunction<T>(funcName)(args...);
    }

      上面的例子中要调用Max和Get函数,这样就行了:

    auto max = ExcecuteFunc<int(int, int)>("Max", 5, 8);
    auto ret = ExcecuteFunc<int(int)>("Get", 5);

      怎么样,比之之前的调用方式是不是简洁直观多了,没有了繁琐的函数指针的定义,没有了反复的调用GetProcAddress及其转换和调用。


      最后看看完整的代码吧。

    复制代码
    #include <Windows.h>
    #include <string>
    using namespace std;
    
    class DllParser
    {
    public:
    
    DllParser()
    {
    }
    
    ~DllParser()
    {
    UnLoad();
    }
    
    bool Load(const string& dllPath)
    {
    m_hMod = LoadLibraryA(dllPath.data());
    if (nullptr == m_hMod)
    {
    printf("LoadLibrary failed
    ");
    return false;
    }
    
    return true;
    }
    
    bool UnLoad()
    {
    if (m_hMod == nullptr)
    return false;
    
    auto b = FreeLibrary(m_hMod);
    if (!b)
    return false;
    
    m_hMod = nullptr;
    return true;
    }
    
    template <typename T>
    std::function<T> GetFunction(const string&funcName)
    {
    FARPROC funAddress = GetProcAddress(m_hMod, funcName.c_str());
    return std::function<T>((T*)(funAddress));
    }
    
    template <typename T, typename... Args>
    typename std::result_of<std::function<T>(Args...)>::type ExcecuteFunc(const string& funcName,Args&&... args)
    {
    return GetFunction<T>(funcName)(args...);
    }
    
    private:
    HMODULE m_hMod;
    };
    复制代码

    c++11 boost技术交流群:296561497,欢迎大家来交流技术。

     
     
  • 相关阅读:
    vscode 整理————开篇之力(一)
    重学c#系列——datetime 和 datetimeoffset[二十一]
    重新点亮shell————什么是shell[一]
    重新整理 .net core 实践篇——— 权限中间件源码阅读[四十六]
    为什么构建容器需要Namespace?
    基于Windows Mobile 5.0的掌上天气预报设计
    使用.NE平台调用服务访问非托管 DLL 中的函数
    .NET Framework 3.0 RC1 开发环境构建
    ASP.NET未处理异常的处理
    基于Silverlight的Windows Phone 推箱子程序开发
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3367404.html
Copyright © 2011-2022 走看看