Codejie's C++ Space

Using C++

练习:LoadLibrary调用DLL中的Class

    使用LoadLibrary函数调用DLL中的函数的方法一般被称为“显式”调用,意义和使用lib的“隐式”调用相对应。
    LoadLibrary调用DLL中的函数的方法比较简单,通过GetProcAddress获得函数的在DLL的地址就可以访问了,但DLL中的Class访问就相对很复杂了(目前我就发现这一种显式调用方式,哪位有其他方法么?)。一个简单的情况就是Class的函数在调用是,其名称是什么?还有Class的contructor函数怎么调用?下面的代码将演示下这些问题。
这里是DLL的文件:
    DllMain.h

 1#ifndef __DLLMAIN_H__
 2#define __DLLMAIN_H__
 3
 4#include <string>
 5
 6#define DllExport __declspec(dllexport)
 7
 8extern "C" int DllExport Func(int x);
 9
10extern "C" class DllExport CA
11{
12public:
13    CA(int x);
14    ~CA();
15
16    int Func0();
17    int Func(int x);
18    const std::string& FuncS(int x, const std::string& str) const;
19protected:
20    int _x;
21}
;
22
23
24#endif

    DllMain.cpp
 1#include <iostream>
 2
 3#include "DllMain.h"
 4
 5int Func(int x)
 6{
 7    return x * 10;
 8}

 9
10CA::CA(int x)
11   : _x(x)
12{
13    std::cout << "contructor" << std::endl;
14}

15
16CA::~CA()
17{
18    std::cout << "destructor" << std::endl;
19}

20
21int CA::Func0()
22{
23    return _x;
24}

25
26int CA::Func(int x)
27{
28    return _x * x;
29}

30
31const std::string& CA::FuncS(int x, const std::string &str) const
32{
33    return str;
34}

35

    这里需要.def文件了,因为Class在DLL中的命名不像函数命名那么简单,会被转义的,像CA::Func(int)在DLL的export表中就是?Func@CA@@QAEHH@Z,具体定义说明可参看《xxx的自我修养》一书。因此,这里需要使用.def文件对函数进行重命名,下面是DllMain.def文件内容:
 
1LIBRARY TESTDLL
2EXPORTS
3    Func = Func
4    CA::CA(int= ??0CA@@QAE@H@Z
5    CA::~CA = ??1CA@@QAE@XZ
6    CA::Func0 = ?Func0@CA@@QAEHXZ
7    CA::Func(int= ?Func@CA@@QAEHH@Z
8    ;CA::FuncS(int,std::basic_string<char>&= ?FuncS@CA@@QBEABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@HABV23@@Z
9    CA::FuncS = ?FuncS@CA@@QBEABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@HABV23@@Z


    多说一句,这里.def的编写很需要Depends(Dependency Walker)工具的支持,其是查看DLL的首选工具啊。。


    编译DLL,用下面代码进行测试:
    LoadLib.cpp
 1#include <iostream>
 2#include <string>
 3
 4#include <windows.h>
 5
 6//#include "DllMain.h"
 7
 8#define DllExport __declspec(dllexport)
 9
10extern "C" int DllExport Func(int x);
11
12extern "C" class DllExport CA
13{
14public:
15    CA(int x);
16    ~CA();
17
18    int Func0();
19    int Func(int x);
20    const std::string& FuncS(int x, const std::string& str) const;
21
22private:
23    int _x;
24}
;
25
26typedef int (*func)(int);
27typedef void (WINAPI *PCTOR)(int);
28typedef int (WINAPI *func0)(void);
29typedef int (WINAPI *funcc)(int);
30typedef const std::string& (WINAPI *funcs)(int,const std::string&);
31typedef void (WINAPI *PDTOR)(void);
32
33int main()
34{
35    HINSTANCE hdll;
36    hdll = LoadLibraryA(("../DLLTEST/Debug/DLLTEST.dll"));
37    if(hdll != NULL)
38    {
39        func pf = (func)GetProcAddress(hdll, "Func");
40        std::cout << pf(10<< std::endl;
41        CA* a = (CA*)malloc(sizeof(CA));
42        PCTOR pc = (PCTOR)GetProcAddress(hdll, "CA::CA(int)");
43        _asm { MOV ECX, a } 
44        pc(5);
45        func0 pf0 = (func0)GetProcAddress(hdll, "CA::Func0");
46        _asm {MOV ECX, a }
47        std::cout << pf0() << std::endl;
48        funcc pfc = (funcc)GetProcAddress(hdll, "CA::Func(int)");
49        _asm { MOV ECX, a }
50        std::cout << pfc(10<< std::endl;
51        funcs pfs = (funcs)GetProcAddress(hdll, "CA::FuncS");
52        _asm { MOV ECX, a }
53        std::cout << pfs(0, std::string("hello world")) << std::endl;
54        PDTOR pd = (PDTOR)GetProcAddress(hdll, "CA::~CA");
55        _asm { MOV ECX, a } 
56        pd();        
57        free(a);    
58    }

59    FreeLibrary(hdll);
60    
61    return 0;
62}


    结果还算正常:
1100
2contructor
35
450
5hello world
6destructor
7


    上面的代码基本演示了DLL中Class的简单使用,包括对contructor、destrunctor的调用,有参、无参、多参函数调用,不知道有啥缺陷,但至少Work了,嘿嘿~
    由上述代码可以看出,这种“显式”使用DLL中的Class是非常繁琐和危险的事情,因此我觉得能用“隐式”就不要用“显式”,能静态就不要用动态。。。
    注意到没,代码没有演示继承和虚函数,那是因此我加入Virtual函数,程序就会core,实在搞不定,这里也就没法给出好的方案来,不知道哪位有啥建议么。。。
    上面代码参考了如下地址:
          http://www.codeproject.com/dll/classesexportedusingLL.asp
          http://blog.csdn.net/jdcb2001/archive/2006/11/21/1401569.aspx

posted on 2009-09-24 17:50 codejie 阅读(25288) 评论(8)  编辑 收藏 引用 所属分类: C++

评论

# re: 练习:LoadLibrary调用DLL中的Class[未登录] 2009-09-25 01:17 Liu

最近很高产么,看来在M记没事可干阿

继续写,我也学习学习  回复  更多评论   

# re: 练习:LoadLibrary调用DLL中的Class 2009-09-25 09:59 陈梓瀚(vczh)

鉴于复杂参数的计算也有可能会毁掉ecx,而且你又不能再参数放进去之后再修改ecx,所以你还是老老实实import一个完整的类吧……  回复  更多评论   

# re: 练习:LoadLibrary调用DLL中的Class 2009-09-25 11:43 codejie

@Liu
M记现在还没有想起让我做什么,我也是吃了空,想到啥就写点啥,没目的,估计也‘产’不出什么。。。别学了,省的耽误了你老人家~
另,我在看你A国的代码,那叫一个惨啊,怎么也想不明白,号称‘技术领先’的A国人,怎么会写出这样的代码。。。  回复  更多评论   

# re: 练习:LoadLibrary调用DLL中的Class 2009-09-25 11:46 codejie

@陈梓瀚(vczh)
我也知道这种方式不好,至少virtual我还没有搞定。你说的使用import方式该如何做?能给给实例不?我现在想解决的问题就是,如果只有DLL,没有lib的情况下,如何使用‘显式’方式访问DLL中的Class。  回复  更多评论   

# re: 练习:LoadLibrary调用DLL中的Class 2009-09-25 15:47 溪流

@codejie

只有 DLL(如果不知道函数名,即不给出 .def),同样不能“显式”调用 DLL 中的函数,不是吗?
不过同样可以用你上面的工具找出函数名称,然后 GetProcAddress,然后使用……  回复  更多评论   

# re: 练习:LoadLibrary调用DLL中的Class 2009-09-25 17:10 codejie

@溪流
不知道exports函数名的情况下使用DLL是一种比较极端的情况,不光是函数名称不知道,函数的参数更是一个问题,.def中多数不说明参数的。
这里使用LoadLibrary的‘显式’调用,一般应该多数用于实时加载DLL,而不是程序启动就加载DLL,这样作便于管理程序的内存使用情况,记得在早期的windows16位机器上常用,还有就是利用DLL特性做plugins的程序中。
这里的代码只是我吃了空而突发奇想的,跟你说的一样,现实中应该很少用的。  回复  更多评论   

# re: 练习:LoadLibrary调用DLL中的Class 2012-07-17 09:14 Richard Wei

如果要用显试调用类,建议还是用接口方式吧,导出一个CreateInstance(interface** ppInterface)就可以了,简单又方便,具体参考COM  回复  更多评论   

# re: 练习:LoadLibrary调用DLL中的Class 2012-07-17 09:43 codejie

@Richard Wei
神奇的COM, 庞大的COM, 恐怖的COM。。。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

Using C++

导航

统计

留言簿(73)

随笔分类(513)

积分与排名

最新评论

阅读排行榜

评论排行榜