用DLL为应用程序预留待扩展功能接口

发表于:2007-07-14来源:作者:点击数: 标签:
动态链接函数库(Dynamic Link Library 简称DLL)是组成 Windows 系统的重要元素之一。Windows将构成其系统的大部分程序代码、数据以及经常用到的资源,以动态链接函数库(二进制文件)的形式存贮在磁盘里。本文主要介绍如何在应用程序中预留待扩展功能接口
动态链接函数库(Dynamic Link Library 简称DLL)是组成Windows系统的重要元素之一。Windows将构成其系统的大部分程序代码、数据以及经常用到的资源,以动态链接函数库(二进制文件)的形式存贮在磁盘里。本文主要介绍如何在应用程序中预留待扩展功能接口,以及利用DLL编写这类扩展功能代码的方法。  

应用实例  
  在开发应用程序的时候考虑到以后可能要添加某些新的功能,为避免修改源程序所带来的麻烦,我们可以在开发应用程序的过程中先预留一个扩展功能接口,以后需要扩展功能时,只要把扩展功能部分的代码单独编译成DLL即可。下面是一个示例程序,该示例程序分为应用程序和扩展功能两部分,当应用程序收到WM_CREATE消息时,检查是否有扩展功能,若有则装入;否则返回。该程序在Windows 95下,用Borland c++ 4.5调试通过。  

  /*------PRAC.C 应用程序部分------*/  

  #include <windows.h>  

  #include "prac.h"  

  int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);  

  long FAR PASCAL MainWndProc(HWND, WORD, WORD, LONG);  

  void MsgFilter(HWND , WPARAM );  

  FARPROC LpExtProc ;  

  /*------- WinMain() -------*/  

  int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,  

             LPSTR lpszCmdLine, int nCmdShow)  

  {  

   MSG   msg;  

   HWND   hWnd;  

   WNDCLASS wndclass;  

   if ( ! hPrevInstance )  

     {  

      wndclass.style = CS_HREDRAW | CS_VREDRAW;  

      wndclass.lpfnWndProc = MainWndProc;  

      wndclass.cbClsExtra = 0;  

      wndclass.cbWndExtra = 0;  

      wndclass.hInstance = hInstance;  

      wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);  

      wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);  

      wndclass.hbrBackground = GetStockObject (WHITE_BRUSH);  

      wndclass.lpszMenuName = "OurOwnMenu"; //装入应用程序菜单  

      wndclass.lpszClassName = "Application";  

      if ( ! RegisterClass (&wndclass) )  

       return FALSE;  

     }  

   hWnd = CreateWindow ( "Extend Function" ,  

              "应用程序示例",  

              WS_OVERLAPPEDWINDOW,  

              CW_USEDEFAULT,  

              CW_USEDEFAULT,  

              CW_USEDEFAULT,  

              CW_USEDEFAULT,  

              NULL,  

              NULL,  

              hInstance,  

              NULL);  

   If (!hWnd )  

     return FALSE;  

   ShowWindow (hWnd, nCmdShow);  

   UpdateWindow (hWnd);  

   while ( GetMessage (&msg, NULL, 0, 0) )  

     {  

      TranslateMessage (&msg);  

      DispatchMessage (&msg);  

     }  

   return msg.wParam;  

  }  

  /*---------- 主窗口函数 WndProc()-------------*/  

  long FAR PASCAL MainWndProc(HWND hWnd, WORD message,  

                    WORD wParam, LONG lParam)  

  {  

   static HANDLE hLibrary;  

   char szBuf[80];  

   switch(message)  

   {  

     case WM_CREATE:  

     /*读应用程序的初始化文件prac.ini,检查是否有扩展功能的动态链接库,若没有则返回;若有则装入该动态链接函接数库,并取得接口函数的地址,对接口函数进行初始化*/  

       GetPrivateProfileString("MyApp" , "AddMyapp" , "" ,  

                 szBuf,sizeof(szBuf) , "prac.ini");  

       if (szBuf[0] != '\0')  

       if ((hLibrary = LoadLibrary(szBuf)) >= 32)  

        {  

         LpExtProc=(FARPROC)GetProcAddress(hLibrary,  

                  MAKEINTRESOURCE(2));  

         LpExtProc(hWnd , EXTPROC_LOAD);  

        }  

       else  

        MessageBox(hWnd,"Load library failed!","Error",MB_OK);  

       break;  

     case WM_COMMAND:  

       /*函数MsgFilter( )用来过滤菜单消息*/  

       MsgFilter(hWnd , wParam);  

       switch (wParam)  

       {  

         case IDM_COMMAND1: //处理应用程序  

         case IDM_COMMAND2: //定义的菜单功  

         case IDM_COMMAND3: //能,此处省略。  

       }  

       return 0;  

     case WM_DESTROY:  

       if(hLibrary != NULL)  

       FreeLibrary(hLibrary);  

       PostQuitMessage(0);  

       break;  

   }  

   return DefWindowProc(hWnd, message, wParam, lParam);  

  }  

/*下面过滤函数,把菜单消息的来源分成两类,即应用程序本身的菜单消息和来自功能扩展部分的菜单消息。应用程序把值在MIN_FMT至MAX_FMT之间的菜单消息留给待扩展程序使用。如果有来自扩展程序的消息,就通过接口函数LpExtProc()把该消息传送给扩展程序,由扩展程序负责处理该消息*/  

  void MsgFilter(HWND hWnd , WPARAM wParam)  

  {  

   if((wParam >= MIN_FMT)&&(wParam <= MAX_FMT))

    LpExtProc(hWnd , wParam);

   return;

  }

  /*---------------- End of PRAC.C-----------------*/

  /*----------- PRAC.H ----------*/

  #define MIN_FMT       100

  #define MAX_FMT      199

  #define EXTPROC_LOAD   200

  #define IDM_COMMAND1   201

  #define IDM_COMMAND2   202

  #define IDM_COMMAND3   203

  /*---End of PRAC.H ---*/

  ; 应用程序的模块定义文件PRAC.DEF

  NAME     PRAC

  DESCRIPTION  'demonstrate a different system menu'

  EXETYPE    WINDOWS

  STUB      'WINSTUB.EXE'

  CODE      PRELOAD MOVEABLE DISCARDABLE

  DATA     PRELOAD MOVEABLE MULTIPLE

  HEAPSIZE   1024

  STACKSIZE   8192

  EXPORTS    MainWndProc

  ; End of PRAC.DEF

  /*---资源定义文件PRAC.RC---*/

  #include "prac.h"

  OurOwnMenu MENU

  BEGIN

   MENUITEM "Command&1",   IDM_COMMAND1

   MENUITEM "Command&2",   IDM_COMMAND2

   MENUITEM "Command&3",   IDM_COMMAND3

  END

  /*---End of PRAC.RC---*/

  若要扩展上面应用程序的功能,在不改动上述程序的情况下,只需将功能扩展部分的代码编写成动态链接函数库,编译成.DLL文件,并在PRAC.INI文件中加入下面语句,即可达到扩展功能的目的。在PRAC.INI中加入:

  [AddApp]

  AddMyapp=c:\win95\system\extproc.dll

  扩展功能的动态链接函数库代码如下:

  /*-----EXTPROC_DLL.c-----*/

  #include <windows.h>  

  #include <commdlg.h>  

  #include "extproc_dll.h"  

  HMENU hMenu , hExtMenu;  

  HWND hWndExt = NULL;  

  int FAR PASCAL LibMain(HANDLE hModule , WORD wDataSeg,  

              WORD HeapSize , LPSTR lpszCmdLine)  

  {  

   if(HeapSize != 0)  

    UnlockData(0);  

   return 1;  

  }  

  int FAR PASCAL WEP(int SystemExit)  

  {  

   switch (SystemExit)  

    {  

     case WEP_SYSTEM_EXIT:  

                 return 1;  

     case WEP_FREE_DLL:  

                 return 1;  

     default:  

         return 1;  

    }  

  }  

  /*函数FMExtensionProc()即为扩展功能的处理函数,当过滤函数检索到有来自扩展功能的菜单消息时,就调用该函数进行处理。在此仅以设置打印机、选择字体来说明扩展功能的处理过程,读者可根据自己的需要修改*/  

  void FAR PASCAL FMExtensionProc(HWND hWndFMExt , WORD wMessage)  

  {  

   PRINTDLG  pd;  

   CHOOSEFONT fnt;  

   LOGFONT lf;  

   CHOOSECOLOR chclr;  

   DWORD dwColor;  

   DWORD dwCustClrs[16];  

   int i;  

   switch(wMessage)  

     {  

     /*处理FMEVENT_LOAD消息,加载用户扩展功能菜单FMExtMenu*/  

      case EXTPROC_LOAD:  

         hExtMenu = LoadMenu(FMExtInst,"FMExtMenu");  

         hMenu = GetMenu(hWndFMExt);  

         AppendMenu(hMenu,MF_POPUP,hExtMenu ,"扩展功能(&E)");  

         SetMenu(hWndFMExt,hMenu);  

         break;  

     /*下面是用户可自定义的扩展功能代码*/  

      case IDM_PRINTERSETUP: //设置打印机  

        pd.lStructSize = sizeof(PRINTDLG);  

        pd.hwndOwner = hWndFMExt;  

        pd.hDevMode  = NULL;  

        pd.hDevNames = NULL;  

        pd.Flags = PD_RETURNDC|PD_SELECTION|PD_PRINTSETUP;  

        pd.nCopies   = 1;  

        PrintDlg((LPPRINTDLG)&pd);  

        break;  

      case IDM_SELECTFONT: //选择字体  

        fnt.lStructSize = sizeof(CHOOSEFONT);  

        fnt.hwndOwner = hWndFMExt;  

        fnt.hDC     = NULL;  

        fnt.lpLogFont = &lf;  

        fnt.Flags   = CF_SCREENFONTS|CF_EFFECTS;  

        fnt.rgbColors = RGB(0,255,255);  

        fnt.lCustData = 0L;  

        fnt.nFontType = SCREEN_FONTTYPE;  

        fnt.nSizeMin  = 0;  

        fnt.nSizeMax  = 0;  

        ChooseFont(&fnt);  

        break;  

     }  

   return;  

  }  

  /*------------End of EXTPROC_DLL.C------------*/  

  /*----- EXTPROC_DLL.H -----*/  

  #define IDM_PRINTERSETUP 101  

  #define IDM_SELECTFONT  102  

  #define EXTPROC_LOAD   200  

  void FAR PASCAL _export FMExtensionProc(HWND,WORD);  

  /*-----End of EXTPROC_DLL.H -----*/  

  ;资源文件EXTPROC_dll.RC  

  #include "windows.h"  

  #include "extproc_dll.h"  

  FMExtMenu MENU DISCARDABLE  

  BEGIN  

   MENUITEM "Printer&Setup" ,IDM_PRINTERSETUP  

   MENUITEM "Select&Font"  ,IDM_SELECTFONT  

  END  

  ;End of EXTPROC_DLL.RC  

  ;模块定义文件EXTPROC_DLL.DEF  

  LIBRARY EXTPROC  

  DESCRIPTION 'File Manager Extension DLL'  

  EXETYPE WINDOWS  

  CODE PRELOAD MOVEABLE DISCARDABLE  

  DATA PRELOAD SINGLE SHARED  

  HEAPSIZE 1024  

  EXPORTS  

   WEP @1 RESIDENTNAME  

   FMExtensionProc @2  

  ;End of EXTPROC_DLL.DEF

原文转自:http://www.ltesting.net