编写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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章