徐宝吧 关注:4贴子:645
  • 9回复贴,共1

[转帖]VC++ DLL编程笔记

只看楼主收藏回复

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文件 


IP属地:江苏1楼2006-06-13 04:34回复
    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;
    }


    IP属地:江苏2楼2006-06-13 04:34
    回复
      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;
      }


      IP属地:江苏3楼2006-06-13 04:35
      回复
        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的一样.


        IP属地:江苏5楼2006-06-13 04:35
        回复
          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);

          }


          IP属地:江苏6楼2006-06-13 04:36
          回复
            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 <afxver.h>
            #include “global.h”

            #pragma comment (lib,”Extdll.lib”)

            int main( )

            {

            count<<add(2,3)<<endl;

            return 0;

            }

            有待实践体会的是扩展MFC类后的调用


            IP属地:江苏7楼2006-06-13 04:36
            回复
              谢谢转载,谢谢,希望您经常光顾wonglaye.net


              8楼2006-08-19 20:44
              回复
                学习


                IP属地:福建9楼2010-12-19 00:56
                回复
                  你会编程吗?


                  10楼2017-07-12 17:59
                  回复
                    我也叫徐宝


                    来自iPhone客户端11楼2019-02-22 19:52
                    回复