|            
动态链接函数库(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  
 |