編寫Win32 DLL(一)

Source CodeMyDll.zip

環境:Windows 2000 Pro+SP4,MSVC6.0+SP6,IDA4.5
一、爲什麼使用DLL?
----《Programming Applications for Microsoft Windows(Fourth Edition)》(Jeffrey Richter)
1、They extend the features of an application.
    Since DLLs can be dynamically loaded into a process's address space,
an application can determine at run time what actions to perform and then
load the code to execute those actions on demand. For example, a DLL is
useful when one company creates a product and wants to allow other companies
to extend or enhance the product.

2、They can be written in many programming languages.
    You can choose the best language for the job at hand. Perhaps your
application's user interface is best programmed with Microsoft Visual Basic,
but the business logic is better handled by C++. The system allows a Visual
Basic program to load a C++ DLL, a Cobol DLL, a Fortran DLL, and so on.


3、They simplify project management.
    If different groups work on different modules during the development
process, the project is easier to manage. However, an application should ship
with as few files as possible. I know of one company that shipped a product
with one hundred DLLs—up to five DLLs per programmer. The application's
initialization time was horribly slow because the system had to open one
hundred disk files before the program could do anything.


4、They help conserve memory. If two or more applications use the same DLL,
the DLL has its pages in RAM once and the pages are shared by all of the
applications. The C/C++ run-time library is a perfect example. Many applications
use this library. If all these applications link to the static library, the
code for functions such as sprintf, strcpy, malloc, and so on exist in memory
multiple times. However, if all these applications link to the DLL C/C++ run-time
library, the code for these functions is in memory only once, which means that
memory is used more efficiently.


5、They facilitate resource sharing.
    DLLs can contain resources such as dialog box templates, strings, icons,
and bitmaps. Multiple applications can use DLLs to share these resources.


6、They facilitate localization.
    Applications frequently use DLLs to localize themselves. For example, an
application that contains only code and no user interface components can load the
DLL containing localized user interface components.


7、They help resolve platform differences.
    The various versions of Windows offer different functions. Frequently,
developers want to call new functions if they exist on the host version. However,
if your source code contains a call to a new function and your application is about
to run on a version of Windows that doesn't offer that function, the operating
system loader will refuse to run your process. This is true even if you never
actually call the function. If you keep these new functions in a DLL, however,
applications can load on an older version of Windows. Of course, you still cannot
successfully call the function.


8、They can serve special purposes. Windows makes certain features available only
to DLLs. For example, you can install certain hooks (set using SetWindowsHookEx
and SetWinEventHook) only if the hook notification function is contained in a DLL.
You can extend Windows Explorer's shell by creating COM objects that must live
inside a DLL. The same is true for ActiveX controls that can be loaded by a Web
browser to create rich Web pages.

二、創建DLL
1、創建DLL
    DLL可以將變量、函數或C/C++類輸出到其他模塊。首先應該創建一個頭文件,改文件包含想要輸
出的變量(變量類型以及變量名)和函數(函數原型和函數名)。頭文件必須定義用於輸出函數和變量的所以符
號和數據結構。在你的DLL的所以模塊都應該包含該頭文件,該頭文件供DLL程序以及其他可執行模塊使用,
以便簡化程序維護工作。
    以下是一個簡單的DLL程序以及調用實例:
// MyDll.h
#ifdef __cplusplus
extern "C"
{
#endif

#ifdef _BUILD_DLL_
#define EXPORT32 __declspec(dllexport)
#else
#define EXPORT32 __declspec(dllimport)
#endif

EXPORT32 int __stdcall MsgBox(const char *lpText,const char *lpTitle);

#ifdef __cplusplus
}
#endif

//MyDll.c
/*
Compile:
    cl kernel32.lib user32.lib /MD /LD /W4  /G4 MyDll.c
*/
#include
#include

#ifndef _BUILD_DLL_
#define _BUILD_DLL_
#endif
#include "Mydll.h"

int __stdcall DllMain(void *hInstance,unsigned long dwReason,void *lpReserved)
{
    return (TRUE);
}

EXPORT32 int __stdcall MsgBox(const char *lpText,const char *lpTitle)
{
    MessageBox(NULL,lpText,lpTitle,MB_OK);
    
    return (0);
}

//DllTest.c
/*
Compile:
    cl kernel32.lib user32.lib /MD /W4  /G4 DllTest.c
*/
#include
#include "Mydll.h"

#pragma comment(lib,"MyDll.lib")

int main()
{
    MsgBox("This is a test for Win32 DLL","Win32 DLL");

    return (0);
}
    示例執行,如圖:   


2、導出與導入
(1)導出
    __declspec(dllexport)修飾符表示導出符號,DLL被鏈接時,鏈接程序要查找相關的函數、變
量等信息,並自動生成一個.lib文件;該lib文件包含DLL導出符號列表,在其他可執行模塊調用DLL時加載
lib文件就可以直接引用。
    Visual Studio的dumpbin.exe可以查看導出節內容。
C:MyDll>dumpbin -exports MyDll.dll
Microsoft (R) COFF Binary File Dumper Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.


Dump of file MyDll.dll

File Type: DLL

  Section contains the following exports for MyDll.dll

           0 characteristics
    42DAA882 time date stamp Sun Jul 17 11:50:42 2005
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 0000100C _MsgBox@8

  Summary

        1000 .data
        1000 .rdata
        1000 .reloc
        1000 .text

(2)導入
    __declspec(dllimport)修飾符表示導入符號,這個符號可以不要;但是如果編譯器預先知道引
用的符號將從一個DLL的lib文件導入,編譯器能夠生成運行效率稍高的代碼。
C:MyDll>dumpbin -imports DllTest.exe
Microsoft (R) COFF Binary File Dumper Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.


Dump of file DllTest.exe

File Type: EXECUTABLE IMAGE

  Section contains the following imports:

    MyDll.dll
                402038 Import Address Table
                4020C0 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                   0  _MsgBox@8

    MSVCRT.dll
                402000 Import Address Table
                402088 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                  9D  _adjust_fdiv
                  83  __setusermatherr
                  D3  _exit
                  48  _XcptFilter
                 249  exit
                  64  __p___initenv
                  58  __getmainargs
                 10F  _initterm
                  6A  __p__commode
                  6F  __p__fmode
                  81  __set_app_type
                  CA  _except_handler3
                  B7  _controlfp

  Summary

        1000 .data
        1000 .rdata
        1000 .text

3、其他編譯器可調用DLL
    MyDll.h文件中包含了extern "C"修飾符,該修飾符表示按C編譯方式編譯,即函數或變量名前
加_,比如函數名爲MsgBox,編譯後爲_MsgBox;一般情況下MSVC編譯器會改變函數和變量的符號,當鏈接程
序鏈接可執行模塊時就會報找不到符號的錯誤,指定extern "C"後編譯器就不會改變函數或變量符號。修飾
符__stdcall在MSVC中指定函數被編譯爲funcation+@+4*n(n爲函數的參數個數),比如例子中函數MsgBox
編譯爲MsgBox@8,再加上extern "C"修飾符,最終函數MsgBox的形式爲_MsgBox@8,如圖:

如果在其他編譯器中調用應調用_MsgBox@8,而不是MsgBox。
    也可以建立一個.def文件來導出函數,這樣就不會改變函數符號,例如:
EXPORTS
    MsgBox

    編譯:
    cl /c /MD MyDll.c
    link kernel32.lib user32.lib /DLL /DEF:MyDll.def MyDll.obj

    MSVC編譯鏈接時就會直接導出MsgBox,而不是_MsgBox@8。如圖:


函數調用示例:
/*
Compile:
    cl kernel32.lib user32.lib /MD /W4  /G4 DllTest1.c
*/
#include
#include

int main()
{
    HINSTANCE hInst;
   
    typedef int (__stdcall *MSGBOX)(const char *,const char *);
    MSGBOX pMsgBox=NULL;
    hInst=LoadLibrary("MyDll1.dll");
    if(hInst){
        pMsgBox=(MSGBOX)GetProcAddress(hInst,"MsgBox");
        if(pMsgBox){
            pMsgBox("This is a test for Win32 DLL","Win32 DLL");
        }
        FreeLibrary(hInst);
    }   

    return (0);
}


 http://www.cublog.cn/u/6830/showart_36247.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章