Windows Via C/C++ 讀書筆記 13 動態鏈接庫基礎DLL Basics

Windows Via C/C++ 讀書筆記 13 

動態鏈接庫基礎DLL Basics

1. Overview

本章講DLL概念(比一些教程仔細得多),實現方式,並給一個簡單的DLL例子說明代碼如何構建。廢話少說,先上圖。這張圖說明了一個DLL由編寫到鏈接、被調用的全部過程。看這篇文章前,你至少要知道什麼是compile,什麼是link,都幹了些啥。

DLL process

左邊的樹是DLL文件的生成過程:

編寫頭文件,包含了需要導出的函數 變量 類型等。

編寫CPP文件,包含了函數的實現。

3 compileobj文件。

4-5 Link出一個.dll和一個.lib文件。.dll文件被.exe文件調用。.lib文件只在.exe文件通過隱式調用方式調用DLL文件的時候有用。本章的例子就是個隱式鏈接方式,還有一種是顯示鏈接通過API在程序運行時動態加載的方式,後面DLL高級部分會講到。Step9exe鏈接的時候講這個lib文件爲什麼有用。Lib文件包含了dll導出的函數 變量等信息,幷包含這個dll文件的名字,當exe鏈接的時候,它知道它用到的函數不是自己實現的,是需要從外部導入的,通過lib文件可以知道哪些函數是從外部導入的,從哪個dll文件導入。

右邊樹是exe文件編譯鏈接過程。

前三步和dll文件類似,和普通exe文件的完全相同。

區別是:step6,頭文件和DLL導出聲明的頭文件是同一個文件,因此在compile的時候,exe程序已經完全知道了要調用的函數名稱,數據類型等信息。這些信息是compileobj文件必需也僅需的。

Step 9,鏈接的時候必須鏈入lib文件,否則程序在link的過程中,會報無法找到函數實現的錯誤。因爲link的過程會遍歷所有的obj,嘗試尋找所有函數的實現部分。而這些函數都是從外部導入的,肯定是找不到的。當它看到lib文件後,會得知這些函數的實現信息,"哦,在dll中,不鏈接到exe代碼段,執行的時候從dll中映射過來。"

Step10,程序啓動的時候尋找dll文件(尋找dll文件的順序各個操作系統微有不同,見msdn dll path)。找到後把代碼和變量映射到自己的地址空間,如果找不到,會彈一個窗口,"xx.dll找不到!"。它爲什麼會知道哪個dll找不到?Lib文件告訴它了。

2. DLL與進程地址空間

進程在調用DLL之前,需要把dll文件映射到自己的地址空間中,然後就像調用自己的代碼一樣調用dll。前面《Windows Via C/C++ 讀書筆記 11 Memory-Mapped Files(內存映射文件)》講了這部分內容。雖然dll只會被加載一次到Page File,然後被多個進程共享,但是它們之間的靜態變量是不會共享的(copy-on-write方式實現,見筆記11)。這是dll編寫者最常見的問題。

3. 構建一個簡單DLL

注意MYLIBAPI的定義,其實在h文件定義一次就足夠了。

extern "C" 表示生成的函數命名不要用c++的方式,c++會修改命名。不然,這個dll只能被c++程序使用,而不能被其它語言編寫的程序使用。

__declspec(dllimport) 告知dll編譯器需要導出,compiler會在obj文件裏面加入這些信息,link讀到這些信息然後生成dll;也告知exe編譯器,這些函數在dll中找到,不要在obj文件中找。

dumpbin工具可以查看dll文件的導出段(export section),使用-exports開關。Dumpbin使用見筆記11

/***************************************************************************

Module:  MyLib.h

***************************************************************************/

#ifdef MYLIBAPI

// MYLIBAPI should be defined in all of the DLL's source

// code modules before this header file is included.

// All functions/variables are being exported.

#else

// This header file is included by an EXE source code module.

// Indicate that all functions/variables are being imported.

#define MYLIBAPI extern "C" __declspec(dllimport)

#endif

////////////////////////////////////////////////////////////////////////////

// Define any data structures and symbols here.

////////////////////////////////////////////////////////////////////////////

// Define exported variables here. (NOTE: Avoid exporting variables.)

MYLIBAPI int g_nResult;

////////////////////////////////////////////////////////////////////////////

// Define exported function prototypes here.

MYLIBAPI int Add(int nLeft, int nRight);

////////////////////////////// End of File /////////////////////////////////

In each of your DLL's source code files, you should include the header file as follows:

/***************************************************************************

Module: MyLibFile1.cpp

***************************************************************************/

// Include the standard Windows and C-Runtime header files here.

#include <windows.h>

// This DLL source code file exports functions and variables.

#define MYLIBAPI extern "C" __declspec(dllexport)

// Include the exported data structures, symbols, functions, and variables.

#include "MyLib.h"

////////////////////////////////////////////////////////////////////////////

// Place the code for this DLL source code file here.

int g_nResult;

int Add(int nLeft, int nRight) {

   g_nResult = nLeft + nRight;

   return(g_nResult);

}

////////////////////////////// End of File /////////////////////////////////

我的測試文件打印出的dumpbin結果,可以看到導出的變量g_nResult和函數Add

E:/projects/dlltest/Debug>dumpbin -exports dlltest.dll

Microsoft (R) COFF/PE Dumper Version 8.00.50727.762

Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file dlltest.dll

File Type: DLL

  Section contains the following exports for dlltest.dll

    00000000 characteristics

    4A3B8423 time date stamp Fri Jun 19 20:27:15 2009

        0.00 version

           1 ordinal base

           2 number of functions

           2 number of names

    ordinal hint RVA      name

          1    0 000110BE Add = @ILT+185(_Add)

          2    1 00017150 g_nResult = _g_nResult

  Summary

        1000 .data

        1000 .idata

        2000 .rdata

        1000 .reloc

        1000 .rsrc

        4000 .text

       10000 .textbss

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章