VC++动态库导出函数和类

来源:互联网 发布:windows编译php扩展 编辑:程序博客网 时间:2024/04/28 14:58

导出动态库中的函数和类首先需要加载动态库,加载的方式有两种,分为:隐式加载和显示加载。(编译器:VC++ 6.0)
对隐式加载还是显示加载的选择不明白请百度。


(一)隐式加载动态库

新建动态库工程,添加头文件和源文件,用以下几种方式分别导出“加减乘除”4个函数和point类,由于实现函数需要,因此添加了两个头文件。

动态库工程头文件(dlltest.h)代码如下:

#include<windows.h>#include<stdio.h>//_declspec(dllexport)作为导出函数的前缀,但是导出的函数名会发生改变_declspec(dllexport) int add(int a, int b);//extern "C"作为导出函数的前缀,导出的函数名不会发生改变,可以解决C和C++函数//调用时名字改编的问题,但是extern "C"只能导出全局函数extern "C" _declspec(dllexport) int sub(int m, int n);//添加.def文件导出此函数,解决了标准调用(pascal)和c调用之间名字改编的问题。//当实际函数名和def文件设置要导出的函数名一致时,导出的函数按实际名称导出;_declspec(dllexport) int mul(int x, int y);//当二者不一致时,可以按照如下格式导出函数:entryname = internalname_declspec(dllexport) int fun(int i, int j);class _declspec(dllexport) point {public:point(int x, int y);void output();private:int m;int n;};


动态库工程源文件(dlltest.cpp)代码如下:

#include "dlltest.h"int add(int a, int b){return a+b;}int sub(int m, int n){return m-n;}int mul(int x, int y){return x*y;}int fun(int i, int j){return i/j;}point::point(int x, int y){m = x;n = y;}void point::output(){   HWND m_hwnd = GetForegroundWindow();   HDC m_hdc = GetDC(m_hwnd);   char buf[20] = {0};   sprintf(buf,"x=%d, y=%d",m,n);   TextOut(m_hdc, 0, 0, buf, strlen(buf));   ReleaseDC(m_hwnd, m_hdc);}
动态库工程编译成功之后生成引入库文件(dlltest.lib)和动态库文件(dlltest.dll).

导出的函数和类在VC++ 6.0自带的Denpedency Walker中查看如下所示,可以看到有的函数名字已经改变了,而有的函数没有改变:



接下来创建一个对话框工程,在对话框只放置一个按钮,按钮里对动态库的导出函数进行测试,分别创建对话框工程的头文件和源文件。

对话框工程的头文件(dllimport.h)代码如下:

//extern作为前缀声明add是外部定义的,此处也可以用_declspec(dllimport)//做外部声明,效率更高。extern int add(int a, int b);//由于在动态库中定义时前面还添加了extern "C" ,因此这里也必须添加,否//则编译不成功!extern "C" _declspec(dllimport) int sub(int m, int n);<pre name="code" class="cpp">
//_declspec(dllimport)为前缀声明point类为导入类;//extern "C"只能用来导出全局函数,不能导出类和成员函数。class _declspec(dllimport) point {public:point(int x, int y);void output();private:int m;int n;};


对话框工程源文件(dlltest_jiemianDlg.cpp)按钮响应函数添加代码如下:

void CDlltest_jiemianDlg::OnBtnTest() {// TODO: Add your control notification handler code herepoint pt(3,5);pt.output();int num;CString strNum;num = add(1,2);strNum.Format("%d",num);MessageBox(strNum);num = sub(5,3);strNum.Format("%d",num);MessageBox(strNum);}
对话框生成可执行程序(dlltest_jiemian.exe)


当对话框程序静态调用动态库时,需要做到3个步骤即可实现调用:

1>先把动态库的引入库文件和动态库文件放到对话框工程目录或Debug目录;

2>在对话框工程的Project->Settings->Object/library modules:设置栏添加动态库的引入库文件;

3>确保对话框对动态库中的导出函数和类做了声明(即是否包含dllimport.h这类文件)。


经测试,可以调用动态库导出的函数和类,结果如下图:



(二)显示加载动态库

由于显示加载和隐式加载动态库差不太多,这里就简单讲了。


动态库还是之前建立的动态库dlltest.dll,这里只拿其中的sub函数为例作说明:

显示加载和隐式加载声明函数的方式有很大不同,需注意!

头文件添加如下代码,此处的ADDFUC是定义的函数指针,声明sub函数式外部定义:

//>>=======================显式调用动态库dlltest.dll======================>>//注意:显式调用动态库无法导入类和类成员函数!!typedef int (*SUBFUC)(int a, int b);//<<=======================显式调用动态库dlltest.dll======================<<

源文件的按钮响应函数添加如下代码:

void CDlltest_jiemianDlg::OnBtnTest() {// TODO: Add your control notification handler code hereHMODULE hmodule;    int num;CString strNum;hmodule = LoadLibrary("dlltest.dll");if (NULL == hmodule){MessageBox("can not find the dll");return;}    SUBFUC subfun = (SUBFUC)GetProcAddress(hmodule, "sub");if (!subfun){MessageBox("get fun address failure");return;}    num = subfun(5, 3);strNum.Format("%d",num);MessageBox("5-3="+strNum);}

运行结果如下:



由于动态库导出的add函数名字改成成了“?add@@YAHHH@”,因此若要导出add函数,则GetProcAddress函数的第二个参数不能之家些“add”,

而应该写“?add@@YAHHH@”,表示导出动态库的add函数,修改如下:

SUBFUC subfun = (SUBFUC)GetProcAddress(hmodule, "?add@@YAHHH@Z");


动态加载动态库有几个关键函数要注意,具体用法自行百度:

1>HMODULE WINAPI LoadLibrary( _In_ LPCTSTR lpFileName);

2>BOOL WINAPI FreeLibrary( _In_ HMODULE hModule);

3>FARPROC GetProcAddress(HMODULE hModule,LPCSTR lpProcName);


当对话框程序静态调用动态库时,需要做到3个步骤即可实现调用:

1>先把动态库的引入库文件和动态库文件放到对话框工程目录或Debug目录;

2>确保对话框对动态库中的导出函数和类做了声明(即是否包含dllimport.h这类文件)。


尤其注意,不要在对话框工程的Project->Settings->Object/library modules:设置栏添加动态库的引入库文件!




0 0
原创粉丝点击