Chinaunix首页 | 论坛 | 博客
  • 博客访问: 160031
  • 博文数量: 20
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 120
  • 用 户 组: 普通用户
  • 注册时间: 2015-03-27 15:17
文章分类

全部博文(20)

文章存档

2016年(1)

2015年(19)

我的朋友

分类: WINDOWS

2015-05-18 13:08:57

文章地址:

在使用MFC编写程序时,MFC的界面过于古老,要想有一个具有现代感的界面就需要使用第三方的库。然而在使用第三方的皮肤时,程序需要在运行时动态链接到外部库。但这会使程序显得过于臃肿。如程序过分依赖外部的dll文件,当用户无心删掉一个dll文件便会导致程序无法启动。二来本人所写的程序实现功能相对单一,体积不大,为了使程序显得精简,拿来就能用,于是便想到了动态生成dll并动态调用dll这一方法。

这样程序相当于内置了SkinMagic第三方皮肤,而无需再把dll文件放在程序外面。
具体流程:程序开始运行-->生成dll文件-->动态调用dll并加载皮肤-->初始化完成正式运行-->程序关闭-->删除dll文件

想要把dll文件等资源动态导出,就需要先把资源文件加载到程序中。

以下引用http://blog.csdn.net/cardinal_508/article/details/8628709

首先把想要导出的资源导入,这里简单描述DLL资源导入的步骤:

1.在Resource View(资源视图)中查找到相应工程;

2.使用Add(添加)->Resource(资源);

3.选择Imort(插入)资源;

4.在选择资源后弹出Custom ResourceType(自定义资源类型)输入自定义的类型名,至此资源插入完毕;

所需函数:

FindResource确定指定模块中指定类型和名称所在的位置

  1. HRSRC FindResource(HMODULE hModule,  
  2.     LPCTSTR lpName,  
  3.     LPCTSTR lpType)

hModule处理包含资源的可执行文件的模块,NULL值指定了模块句柄指向操作系统通常情况下创建最近过程的相关文件;

lpName指定资源名称;

lpType指定资源的类型,就是上面所自定义资源类型;

SizeofResource返回指定资源字节数大小

  1. DWORD SizeofResource(HMODULE hModule,  
  2.     HRSRC hReslnfo)  

hModule包含资源的可执行文件的句柄,如果为空当前文件(我是这么理解的);

hReslnfo资源句柄,句柄必须使用FindResource函数创建;

如果返回0则失败,通过DWORD的寻址范围可看出文件的最大大小;

LoadResource该函数装载指定资源到全局储存器

  1. HGLOBAL LoadResource(HMODULE hModule,  
  2.     HRSRC hReslnfo)  

参数同上

如果运行成功返回相关资源的句柄,如果运行失败返回NULL

LockResource锁定内存中的指定资源;

  1. LPVOID LockResource(HGLOBAL hResData)  

失败返回NULL,成功返回资源指针,可以重IO输出成文件

释放相关资源函数:

CloseHandle ()

FreeResource ()

代码如下:


  1. HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_DLL1), TEXT("DLL"));  
  2. if (NULL == hRsrc){  
  3.     return;}  
  4. DWORD dwSize = SizeofResource(NULL, hRsrc);   
  5. if (0 == dwSize){  
  6.     return;}  
  7. HGLOBAL gl = LoadResource(NULL, hRsrc);   
  8. if (NULL == gl){  
  9.     return;}   
  10. LPVOID lp = LockResource(gl);   
  11. if (NULL == lp){  
  12.     return;}  
  13. CString filename="dd.dll";  
  14. HANDLE fp= CreateFile(filename ,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);   
  15. DWORD a;   
  16. if (!WriteFile (fp,lp,dwSize,&a,NULL)){  
  17.     return;}  
  18. CloseHandle (fp);  
  19. FreeResource (gl);  
生成好dll文件就可以动态调用了

以下引用http://blog.csdn.net/freebot/article/details/4312191

动态调用动态库步骤:


1、创建一个函数指针,其指针数据类型要与调用的DLL引出函数相吻合。
2、通过Win32 API函数LoadLibrary()显式的调用DLL,此函数返回DLL的实例句柄。
3、通过Win32 API函数GetProcAddress()获取要调用的DLL的函数地址,把结果赋给自定义函数的指针类型。
4、使用函数指针来调用DLL函数。
5、最后调用完成后,通过Win32 API函数FreeLibrary()释放DLL函数。

例如:在test.dll文件中有一个int Add(int a,int b)的函数,现在调用test.dll文件的Add函数,如下所示:



  1. typedef int (_stdcall * AddProc)(int , int );//定义函数指针类型  
  2.   
  3.  HINSTANCE hInst;  
  4.   
  5.  hInst=LoadLibrary("test.dll");//动态加载Dll  
  6.   
  7.  AddProc Add=(AddProc)GetProcAddress(hInst,"add");//获取Dll的导出函数  
  8.    
  9.  if(!Add)  
  10.  {  
  11.   MessageBox("获取Add函数地址失败!");  
  12.  }  
  13.   
  14.  CString stradd;  
  15.  stradd.Format("5+3=%d",Add(5,3));  
  16.  MessageBox(stradd);  
  17.   
  18.  ::FreeLibrary(hInst);//释放Dll函数  



在实际的MFC编程中,dll文件一般在使用前加载完成,对于皮肤文件需要在MFC的InitInstance()初始化函数运行时就要加载完毕。
部分代码如下:

  1. CWinApp::InitInstance();
  2. //-----------------------------------------------------------------将DLL文件及SMF文件加入资源中,程序启动时生成

  3.     //-----------生成
  4.     HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_DLL1),"DLL"); //寻找DLL文件 确定指定模块中指定类型和名称所在的位置
  5.     if (NULL == hRsrc)
  6.         AfxMessageBox("寻找DLL文件失败!");
  7.     else
  8.     {
  9.         DWORD dwSize = SizeofResource(NULL, hRsrc); //返回指定资源字节数大小
  10.         HGLOBAL gl = LoadResource(NULL, hRsrc); ////该函数装载指定资源到全局储存器
  11.         if (NULL == gl)
  12.             AfxMessageBox("装载资源失败!");
  13.         LPVOID lp = LockResource(gl); //锁定内存中的指定资源
  14.         CString filename="DiskWatcher.dll";
  15.         HANDLE fp= CreateFile(filename ,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
  16.         DWORD a;
  17.         while(!WriteFile(fp,lp,dwSize,&a,NULL))
  18.             break;
  19.         CloseHandle(fp);
  20.         FreeResource(gl); //写完了
  21.     }

  22.     //------------动态调用
  23.      typedef int (_stdcall * InitProc)(HINSTANCE hInstance, LPCTSTR lpApplication , LPCTSTR lpReserved1,LPCTSTR lpReserved2);//定义函数指针类型-初始化
  24.      typedef int (_stdcall * IoadProc)(HMODULE hModule,LPCTSTR lpSkinName ,LPCTSTR lpType); //加载
  25.      typedef int (_stdcall * SetWindow)( HWND hWnd , LPCTSTR lpSkinName ); //应用
  26.      typedef int (_stdcall * SetDialog)( LPCTSTR szSkinName );    //应用
  27.      typedef int (_stdcall * SetSingleDialog)( HWND hWnd , LPCTSTR szSkinName );
  28.      typedef int (_stdcall * EnableWindowScrollbar)(HWND hWnd ,int fnBar);//
  29.     
  30.      HINSTANCE hInst;
  31.      hInst=LoadLibrary(".\\DiskWatcher.dll");//动态加载Dll
  32.      InitProc InitSkinMagicLib=(InitProc)GetProcAddress(hInst,"InitSkinMagicLib");//获取Dll的导出函数
  33.      IoadProc LoadSkinFromResource=(IoadProc)GetProcAddress(hInst,"LoadSkinFromResource");//获取Dll的导出函数
  34.      SetWindow SetWindowSkin=(SetWindow)GetProcAddress(hInst,"SetWindowSkin");
  35.      SetDialog SetDialogSkin=(SetDialog)GetProcAddress(hInst,"SetDialogSkin");
  36.      SetSingleDialog SetSingleDialogSkin=(SetSingleDialog)GetProcAddress(hInst,"SetDialogSkin");
  37.      EnableWindowScrollbar EnableWindowScrollbarSkin = (EnableWindowScrollbar)GetProcAddress(hInst,"SetDialogSkin");

当然用完了就要删除,删除命令需要写在程序窗口关闭时:

  1. INT_PTR nResponse = dlg.DoModal();
  2.     ::FreeLibrary(hInst);//-----------------------释放
  3.     remove(".\\DiskWatcher.dll");


阅读(3850) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~