VC++ DLL编程笔记(一)
Published by wonglaye 三月 24th, 2006 in VC
动态链接库DLL同静态Lib链接的区别在于:程序在编译成可执行文件时会把静态链接库中的程序拷进可执行文件中,所以Lib文件是不用同可执行 文件一同发布的。而链接到动态库DLL中时要通过一个Lib文件,Lib文件保存了函数或类在DLL中的入口地址,可执行文件中相应存放的也是函数地址, 所以DLL和Lib要同可执行文件一起发布。
1. VC中支持的DLL种类:Non MFC DLL,Regular DLL,Exetension DLL
Non MFC DLL 非MFC动态链接库:不使用MFC类库结构,直接用C写,输出函数用标准C接口,能被非MFC程序调用
Regular DLL 正则动态链接库:使用MFC编写,源文件中有继承自CWinApp的类,只能被MFC调用;正则Dll又分成静态连接到MFC的和动态链接到MFC的,在创建时会看到。
Extension DLL 扩展动态链接库:实现从MFC继承下来的新类,输出MFC新子类,只能被MFC调用
实践:在新建菜单中选择新建工程Win32 Dynamic Link Library,选择simple project,加入自己的函数MyFunction:
#include “stdafx.h”
//#include “DLL.h”
//也可省略Extern “C”,它的作用是使其他语言可以访问到
extern “C” _declspec(dllexport) int MyFunction();//可以将这一行放在DLL.h里,也可用.def文件创建
//入口地址
BOOL APIENTRY DllMain( HANDLE hModule, //指向自身的句柄
DWORD ul_reason_for_call, //Dll被调用的原因
LPVOID lpReserved//保留参数
)
{
switch (ul_reason_for_call)//调用原因
{
case DLL_PROCESS_ATTACH://进程被调用
case DLL_THREAD_ATTACH://线程被调用
case DLL_THREAD_DETACH://进程被停止
case DLL_PROCESS_DETACH://线程被停止
break;
}
return TRUE;
}
int MyFunction()//自定函数
{
return 886;
}
编译后即可生成DLL文件和相应的Lib文件
VC++ DLL编程笔记(二)
Published by wonglaye 三月 25th, 2006 in VC
调用DLL的方法:显式调用 隐式调用
显调:用LoadLibrary或AfxLoadLibrary显式调入Dll,再用GetProcAddress引入函数,最后用FreeLibrary或AfxFreeLibrary(参数是AfxLoadLibrary返回的句柄)释放Dll
隐调:需要加入动态链接库Lib文件,不需要调用LoadLibrayr或AfxLoadLibrary
实践隐调:新建一个工程DllDemo,将之前的Dll.dll和Dll.lib拷贝到工程目录下
// DllDemo.cpp :
#include “stdafx.h”
#include “stdio.h”
//#include “DllDemo.h”
#pragma comment(lib,”Dll.lib”) //引入Dll.lib,也可在设置中link
extern “C” _declspec(dllimport) int MyFunction();//导入MyFunction,也可放在头文件中,如果dll中有加extern,导入时也要加extern
int main(int argc, char* argv[])
{
int result=MyFunction();
printf(”The number is %d \\r\n”,result);
return 0;
}
VC++DLL编程笔记(三)
Published by wonglaye 四月 5th, 2006 in VC
Dll的显式调用
将调试好的DLL文件和LIb文件拷贝到工程目录
主调函数的构造过程大致为:
1.typedef一个以dll内函数为类型、参数相同的函数指针,并用这个函数指针声明一个实例
2.LoadLibrary(”dll文件名”)返回一个HINSTANCE hInstance
3.GetProcAddress(hInstance,”被调函数名”)返回给typedef定义的函数类型指针的实例
4.调用这个函数实例
5.最后别忘了FreeLibrary(hInstance)
实践:
新建一个Win32Consol,在cpp文件中输入
#include “stdafx.h”
#include “stdio.h”
#include “windows.h”
int main(int argc, char* argv[])
{
typedef int (*pMyFunction) ();
HINSTANCE hDll;
pMyFunction MyFunction;
hDll=LoadLibrary(”Dll.dll”);
MyFunction=(pMyFunction)GetProcAddress(hDll,”MyFunction”);
int result=MyFunction();
printf(”the result is %d”,result);
FreeLibrary(hDll);
return 0;
}
VC++DLL编程笔记(四)
Published by wonglaye 四月 12th, 2006 in VC
最近有点跑题…继续dll的学习
导出dll中的变量和类
之前的笔记是导出dll的函数(显调和隐调),这次导出变量和类的方法与之相同
1.导出变量,超简单,只须在Win32DLL工程”DLL”中的DLL.h中声明extern _declspec(dllimport) int MyVar;并在DLL.cpp中初始化一下int MyVar=100;
在调用工程DllDemo中声明一下就使用了:
//DllDemo.cpp
#pragma comment(lib,”Dll.lib”)
extern _declspec(dllimport) int MyVar;
….
2.导出类
在Win32DLL工程中新建类MyClass:
//MyClass.h
class _declspec(dllexport) MyClass //类的声明中加_declspec(dllexport)
{
public:
MyClass();
~MyClass();
int MyClassVar;
}; //不要忘了加分号!!//MyClass.cpp
#include “stdafx.h” //在VC中一定要加这一头文件
#include “MyClass.h”
MyClass::MyClass()
{
this->MyClassVar=300;
}
MyClass::~MyClass()
{
}
在DLL.cpp中不必加任何内容
将DLL工程中的MyClass头文件包含在调用工程DllDemo中,并声明一下MyClass类,就可以使用该类了:
///DllDemo.cpp
#include “stdafx.h”
#include “stdio.h”
#include “DllDemo.h”
#include “MyClass.h” //包含MyClass的定义文件,否则找不到MyClass类而报错
#pragma comment(lib,”Dll.lib”)
class _declspec(dllimport) MyClass;
int main(int argc, char* argv[])
{
MyClass MyClass_;
printf(”The var MyClassVar is %d \\r\n”,MyClass_.MyClassVar);
return 0;
}
要总结的是导出Dll中的类时要包含该类的头文件。
VC++Dll编程(五)
Published by wonglaye 五月 10th, 2006 in VC
Regular Dll之 静态链接到MFC
Regular Dll的特点在于
1.它是MFC的,即Dll内部可以使用MFC
2.它是规则的,即Dll的接口是C的而不能是MFC
3. 规则Dll包含一个从CWinApp继承下来的类
Rgular Dll又分两类
1. 静态链接到MFC的Dll
2.动态链接到MFC的Dll (这个需要进行一个模块切换以使应用程序能够找到正确的资源模板,原因是主程序和Dll可能有相同ID的资源,会发生冲突)
在创建MFC Dll使可以选择是静态链接到MFC还是动态链接到MFC,创建后也可以通过
project–>settings–>General in MS Foundation Class里修改
当然静态链接到MFC的程序会较大。
在静态Regular Dll中,可以像一般的MFC应用程序一样添加对话框等MFC类,像非MFC Dll一样来声明函数:
externc “C” _declspen(dellexport) void showdlg (void)
{
CYourDlg yourdlg; //CYourDlg是自己通过ClassWizzard定义的对话框类
yourdlg.DoModal(); //当应用程序调用改Dll的showdlg()方法时显示一个模式对话框
}
剩下的工作就是在应用程序中链接该Dll,并调用Dll中的函数,调用静态Regular Dll的方法同样可以使用显调或阴调,方法同非MFC Dll的一样.
VC++ DLL编程笔记(六)
Published by wonglaye 五月 19th, 2006 in VC
继续学习,规则DLL之动态链接到MFC
应用程序(主调程序)和每个DLL都有一个全局唯一的HINSTANCE句柄(模块),不管是在主调程序还是DLL中,加载资源都要参考 HINSTANCE。主调程序和DLL都可能包含自己的资源,这些资源的ID却不是全局的,可能出现不同HINSTANCE中资源ID号相同的情况而发生 加载冲突,表现就是EXE打算调用DLL中的对话框却显示的是EXE中的对话框。
使用了共享的MFC库之后,默认情况下使用主程序的句柄来加载资源,所以如果DLL和应用程序的资源ID有冲突时,需要进行一个模式切换。
(26日加)如果资源ID不冲突需不需要切换呢?实做后发现即使DLL和应用程序没有资源冲突也要切换,如果不切换应用程序不能找到DLL中的资源(/26日加)
模式切换的方式有三:
方法一: 在DLL接口函数中使用AFX_MANAGE_STATE(AfxGetStaticModuleState());语句来自动对模块进行切换和现场恢复。
具体如下,接笔记五中的例子,在主调程序中也创建一个ID号同Dll中的对话框ID号相同的对话框,在DLL的接口函数showdlg中加入:
void showdlg (void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CDialog dlg (IDD_XXX);
dlg.DoModal();
}
方法二:在DLL接口函数中使用AfxGetResourceHandle()和AfxSetResourceHandle (HINSTANCE),相对方法一中只有退出接口函数才恢复现场,方法二更加灵活,使用方法十分类似对Font,Brush等的编程,在切换之前先保存 系统句柄,切换之后恢复。
AfxGetResourceHandle()用于获得当前资源句柄
AfxSetResourceHandle()用于设置程序要用的资源句柄
如下:
CXXXDllApp theApp;
void showdlg (void)
{
//先保存当前的资源句柄,也就是应用程序的句柄
HINSTANCE save_hInstance=AfxGetResourceHandle();
//设置当前资源句柄为Dll的INSTANCE句柄
AfxSetResourceHandle(theApp.m_hInstance);
CDialog dlg(IDD_XXX);
dlg.DoModal();
//恢复原来的
AfxSetResourceHandle(save_hInstance);
}
方法三 在应用程序中也就是主调函数中进行切换,场景换到应用程序中
使用GetModuleHandle()或AfxGetResourceHandle()得到句柄
使用AfxSetResourceHandle()来切换句柄
将DLL中接口函数showdlg()恢复成原来的样子:
void showdlg() { CDialog dlg(IDD_XXX); dlg.DoModal();}
在应用程序调用Dll的响应函数中进行模块切换
void CXXXDlg :: OnButton1 ( )
{
//参数为NULL得到exe的句柄,也可用AfxGetResourceHandle
HINSTANCE exe_hInstance=GetModuleHandle(NULL);
//参数为相应dll文件名得到dll的句柄
HINSTANCE dll_hInstance=GetModuleHandle("XXXDll.dll");
//设置成Dll的句柄
AfxSetResourceHandle(dll_hInstance);
//调用Dll中的接口
showdlg();
//调用完毕恢复为EXE的句柄
AfxSetResourceHandle(exe_hInstance);
}
VC++ DLL编程笔记(七)
Published by wonglaye 六月 1st, 2006 in VC
VISIUAL.COM的留言验证码有问题,看到后请”维修”,你的blog上也不留个联系方式啊青年
扩展Dll内部不仅可以使用MFC,而且接口同样也是MFC的,目的是为了从MFC类库中派生可重用的类,由于扩展Dll需要共享MFC库,所以只有以共享MFC方式生成的EXE才能使用扩展DLL。
扩展DLL不包含CWinApp对象,而是自动添加DllMain()作为入口进行初始化和清理工作。
扩展DLL定义了一系列的宏方便程序的编写
AFX_EXT_CLASS 用来声明导入导出类
AFX_EXT_API 用来声明导入导出函数
AFX_EXT_DATA 用来声明导入导出变量
使用统一的一个宏就可表示输入输出不同含义,这些宏的含义取决于_AFXEXT是否定义:在DLL中定也了_AFXEXT则表示输出,没有定义则表示输入,这些宏的的定义在 afxver.h
扩展DLL一般使用隐式调用(好像显调会出错,实践后再补上)
应该说扩展DLL的调用同Regular DLL的隐式调用没有什么不同,扩展DLL要紧的是其内部对MFC类的扩展,而不是接口
隐式调用:
在Dll中添加一个对话框类,将其声明中加入AFX_EXT_CLASS,表示为输出类
//Extdll.dll
Class AFX_EXT_CLASS CExtDialog : public CDialog
在主调函数中相应调用处加入
#include ExtDialog.h
#pragma comment(lib,”ExtDll.lib”) //隐调
void CCallDialog :: OnButtion()
{
CExtDialog dlg;
dlg.DoModal();
}
调用需要 1. Dll扩展类的头文件
2. Dll文件
3. Lib文件
导出函数和变量的过程:首先在DLL中添加global.h和global.cc(示例)文件
在头文件中用宏声明为输出:
.h:
extern “C” int AFX_EXT_DATA total;
extern “C” int AFX_EXT_API add (int ,int);
在cpp中实现
.cpp:
#include “stdAfx.h”
#include “global.h”
extern “C” int total;
int add (int ,int y)
{
total=x+y;
return total;
}
调用时:
#include #include “global.h” #pragma comment (lib,”Extdll.lib”) int main( ) { count< }下载本文