導航:首頁 > 源碼編譯 > dll文件是編譯後的嗎

dll文件是編譯後的嗎

發布時間:2022-06-10 21:04:13

1. dll是什麼文件的後綴名

DLL文件(Dynamic Linkable Library 即動態鏈接庫文件),是一種不能單獨運行的文件,它允許程序共享執行特殊任務所必需的代碼和其他資源 比較大的應用程序都由很多模塊組成,這些模塊分別完成相對獨立的功能,它們彼此協作來完成整個軟體系統的工作。可能存在一些模塊的功能較為通用,在構造其它軟體系統時仍會被使用。在構造軟體系統時,如果將所有模塊的源代碼都靜態編譯到整個應用程序 EXE 文件中,會產生一些問題:一個缺點是增加了應用程序的大小,它會佔用更多的磁碟空間,程序運行時也會消耗較大的內存空間,造成系統資源的浪費;另一個缺點是,在編寫大的 EXE 程序時,在每次修改重建時都必須調整編譯所有源代碼,增加了編譯過程的復雜性,也不利於階段性的單元測試。 Windows 系統平台上提供了一種完全不同的較有效的編程和運行環境,你可以將獨立的程序模塊創建為較小的 DLL 文件,並可對它們單獨編譯和測試。在運行時,只有當 EXE 程序確實要調用這些 DLL 模塊的情況下,系統才會將它們裝載到內存空間中。這種方式不僅減少了 EXE 文件的大小和對內存空間的需求,而且使這些 DLL 模塊可以同時被多個應用程序使用。Windows 自己就將一些主要的系統功能以 DLL 模塊的形式實現。 一般來說,DLL 是一種磁碟文件,以.dll、.DRV、.FON、.SYS 和許多以 .EXE 為擴展名的系統文件都可以是 DLL。它由全局數據、服務函數和資源組成,在運行時被系統載入到調用進程的虛擬空間中,成為調用進程的一部分。如果與其它 DLL 之間沒有沖突,該文件通常映射到進程虛擬空間的同一地址上。DLL 模塊中包含各種導出函數,用於向外界提供服務。DLL 可以有自己的數據段,但沒有自己的堆棧,使用與調用它的應用程序相同的堆棧模式;一個 DLL 在內存中只有一個實例;DLL 實現了代碼封裝性;DLL 的編制與具體的編程語言及編譯器無關。 在 Win32 環境中,每個進程都復制了自己的讀/寫全局變數。如果想要與其它進程共享內存,必須使用內存映射文件或者聲明一個共享數據段。DLL 模塊需要的堆棧內存都是從運行進程的堆棧中分配出來的。Windows 在載入 DLL 模塊時將進程函數調用與 DLL 文件的導出函數相匹配。Windows 操作系統對 DLL 的操作僅僅是把 DLL 映射到需要它的進程的虛擬地址空間里去。DLL 函數中的代碼所創建的任何對象(包括變數)都歸調用它的線程或進程所有。 調用方式: 1、靜態調用方式:由編譯系統完成對 DLL 的載入和應用程序結束時 DLL 卸載的編碼(如還有其它程序使用該 DLL,則 Windows 對 DLL 的應用記錄減1,直到所有相關程序都結束對該 DLL 的使用時才釋放它,簡單實用,但不夠靈活,只能滿足一般要求。 隱式的調用:需要把產生動態連接庫時產生的 .LIB 文件加入到應用程序的工程中,想使用 DLL 中的函數時,只須說明一下。隱式調用不需要調用 LoadLibrary() 和 FreeLibrary()。程序員在建立一個 DLL 文件時,鏈接程序會自動生成一個與之對應的 LIB 導入文件。該文件包含了每一個 DLL 導出函數的符號名和可選的標識號,但是並不含有實際的代碼。LIB 文件作為 DLL 的替代文件被編譯到應用程序項目中。 當程序員通過靜態鏈接方式編譯生成應用程序時,應用程序中的調用函數與 LIB 文件中導出符號相匹配,這些符號或標識號進入到生成的 EXE 文件中。LIB 文件中也包含了對應的 DL L文件名(但不是完全的路徑名),鏈接程序將其存儲在 EXE 文件內部。 當應用程序運行過程中需要載入 DLL 文件時,Windows 根據這些信息發現並載入 DLL,然後通過符號名或標識號實現對 DLL 函數的動態鏈接。所有被應用程序調用的 DLL 文件都會在應用程序 EXE 文件載入時被載入在到內存中。可執行程序鏈接到一個包含 DLL 輸出函數信息的輸入庫文件(.LIB文件)。操作系統在載入使用可執行程序時載入 DLL。可執行程序直接通過函數名調用 DLL 的輸出函數,調用方法和程序內部其 它的函數是一樣的。 2、動態調用方式:是由編程者用 API 函數載入和卸載 DLL 來達到調用 DLL 的目的,使用上較復雜,但能更加有效地使用內存,是編制大型應用程序時的重要方式。 顯式的調用: 是指在應用程序中用 LoadLibrary 或 MFC 提供的 AfxLoadLibrary 顯式的將自己所做的動態連接庫調進來,動態連接庫的文件名即是上面兩個函數的參數,再用 GetProcAddress() 獲取想要引入的函數。自此,你就可以象使用如同本應用程序自定義的函數一樣來調用此引入函數了。在應用程序退出之前,應該用 FreeLibrary 或 MFC 提供的 AfxFreeLibrary 釋放動態連接庫。直接調用 Win32 的 LoadLibary 函數,並指定 DLL 的路徑作為參數。LoadLibary 返回 HINSTANCE 參數,應用程序在調用 GetProcAddress 函數時使用這一參數。GetProcAddress 函數將符號名或標識號轉換為 DLL 內部的地址。程序員可以決定 DLL 文件何時載入或不載入,顯式鏈接在運行時決定載入哪個 DLL 文件。使用 DLL 的程序在使用之前必須載入(LoadLibrary)載入DLL從而得到一個DLL模塊的句柄,然後調用 GetProcAddress 函數得到輸出函數的指針,在退出之前必須卸載DLL(FreeLibrary)。 正因為DLL 有佔用內存小,好編輯等的特點有很多電腦病毒都是DLL格式文件。但不能單獨運行。 動態鏈接庫通常都不能直接運行,也不能接收消息。它們是一些獨立的文件,其中包含能被可執行程序或其它DLL調用來完成某項工作的函數。只有在其它模塊調用動態鏈接庫中的函數時,它才發揮作用。

2. DLL文件編譯,高手請指教。

DLL文件即動態鏈接庫文件,是一種可執行文件,它允許程序共享執行特殊任務所必需的代碼和其他資源。Windows提供的DLL文件中包含了允許基於Windows的程序在Windows環境下操作的許多函數和資源。

DLL多數情況下是帶有DLL擴展名的文件,但也可能是EXE或其他擴展名。它們向運行於Windows操作系統下的程序提供代碼、數據或函數。程序可根據DLL文件中的指令打開、啟用、查詢、禁用和關閉驅動程序。

DLL的全稱是Dynamic Link Library, 中文叫做「動態鏈接文件」。在Windows操作系統中, DLL對於程序執行是非常重要的, 因為程序在執行的時候, 必須鏈接到DLL文件, 才能夠正確地運行。而有些DLL文件可以被許多程序共用。因此, 程序設計人員可以利用DLL文件, 使程序不至於太過巨大。但是當安裝的程序越來越多, DLL文件也就會越來越多, 如果當你刪除程序的時候, 沒有用的DLL文件沒有被刪除的話, 久而久之就造成系統的負擔了。

DLL是動態連接庫。使用動態連接庫的一些好處是:
1.多個應用程序共享代碼和數據:比如Office軟體的各個組成部分有相似的外觀和功能,這就是通過共享動態連接庫實現的。
2.在鉤子程序過濾系統消息時必須使用動態連接庫。
3.動態連接庫以一種自然的方式將一個大的應用程序劃分為幾個小的模塊,有利於小組內部成員的分工與合作。而且,各個模塊可以獨立升級。如果小組中的一個成員開發了一組實用常式,他就可以把這些常式放在一個動態連接庫中,讓小組的其他成員使用。
4.為了實現應用程序的國際化,往往需要使用動態連接庫。使用動態連接庫可以將針對某一國家、語言的信息存放在其中。對於不同的版本,使用不同的動態連接庫。在使用AppWizard生成應用程序時,我們可以指定資源文件使用的語言,這就是通過提供不同的動態連接庫實現的。
VC++、C++ Builder、Delphi都可以編寫DLL文件。Visual Basic 5.0以上版本也可以編寫一種特殊的DLL,即ActiveX DLL。

DLL不是獨立運行的程序,它是某個程序的一個部分,它只能由所屬的程序調用。用戶不能,也不需要打開它。

3. 如何編譯生成dll文件以及如何調用dll文件

1.vs2015下生成DLL文件
文件->新建->項目
點擊確定選擇dll選項和空項目選項
點擊完成
為項目添加c++源文件mydll.cpp
[cpp] view plain
在CODE上查看代碼片派生到我的代碼片
extern "C" // 此處extern "c" 為解決c/c++兼容問題
{
_declspec(dllexport)int add(int a, int b)
{
return a + b;
}
extern "C"
{
_declspec(dllexport)int sub(int a, int b)
{
return a - b;
}
}
編譯生成 成功後會在工程根目錄生成Win32Project1.dll文件
2.對dll文件的調用
顯示調用動態鏈接庫
新建C++工程
把生成的 Win32Project1.dll 文件拷貝到 剛才新建的工程目錄下
在工程中新建源文件寫入代碼為
[cpp] view plain
在CODE上查看代碼片派生到我的代碼片
#include<iostream>
#include<windows.h>
void main()
{
HINSTANCE mydll = LoadLibrary("Win32Project1.dll"); //載入dll文件
if (mydll == NULL)
{
return;
}
int(*add)(int, int) =( int (*)(int ,int )) GetProcAddress(mydll, "add");//獲取函數指針
/*
等價於
typedef int(*myadd)(int, int); //給 函數指針int (*)(int, int ) 取別名 myadd
myadd a = (myadd) GetProcAddress(mydll,"add"); //獲取函數地址
*/
if (add == NULL)
{
return;
}
std::cout << add(1, 2);
std::cin.get();
}
編譯並運行即可。

4. 易語言編譯後什麼也沒有,只有一個DLL文件

編譯出來是dll,是因為你在創建易語言的時候選擇了創建windows動態連接庫文件。
只有你在創建的時候選擇windows窗口程序 才可以編譯出exe文件~

5. 什麼是.dll文件

DLL是一個包含可由多個程序同時使用的代碼和數據的庫。例如,在Windows操作系統中,Comdlg32 DLL執行與對話框有關的常見函數。因此,每個程序都可以使用該DLL中包含的功能來實現「打開」對話框。這有助於促進代碼重用和內存的有效使用。

DLL的優點

當程序使用DLL時,具有以下的優點:使用較少的資源,當多個程序使用同一個函數庫時,DLL可以減少在磁碟和物理內存中載入的代碼的重復量。這不僅可以大大影響在前台運行的程序,而且可以大大影響其他在Windows操作系統上運行的程序。推廣模塊式體系結構DLL有助於促進模塊式程序的開發。

6. 創建asp.net 網站.編譯後會生成dll文件嗎

ascx是用戶控制項,在頁面上直接引用就可以了,不需要封裝,你發布的時候,編譯器會幫你編譯成dll,不用擔心代碼安全問題。頁面上用的時候在頂端添加引用然後在要用的地方加上個標簽就可以了================================================================補充================================================================你可以創建一個類項目,然後在項目里重載你要的控制項,編譯出來的就是一個DLL,在項目toolbar里添加引用,就可以使用了。

7. dll動態鏈接庫文件不是已經被編譯和鏈接好的二進制文件了嗎怎麼還會被損壞呢

當然可以修改了。Dll和EXE文件格式類似,你的EXE文件可以被修改,DLL文件當然也可以被修改了。Dll中除去重定位等信息,還包含機器碼也就是CPU可執行的指令,這些都是可以修改的。

8. .dll文件是用什麼編寫的呀

DLL是一種特殊的可執行文件。說它特殊主要是因為一般它都不能直接運行,需要宿主程序比如*.EXE程序或其他DLL的動態調用才能夠使用。簡單的說,在通常情況下DLL是經過編譯的函數和過程的集合。
使用DLL技術主要有以下幾個原因:

一、減小可執行文件大小。
DLL技術的產生有很大一部分原因是為了減小可執行文件的大小。當操作系統進入Windows時代後,其大小已經達到幾十兆乃至幾百兆。試想如果還是使用DOS時代的單執行文件體系的話一個可執行文件的大小可能將達到數十兆,這是大家都不能接受的。解決的方法就是採用動態鏈接技術將一個大的可執行文件分割成許多小的可執行程序。

二、實現資源共享。
這里指的資源共享包括很多方面,最多的是內存共享、代碼共享等等。早期的程序員經常碰到這樣的事情,在不同的編程任務中編寫同樣的代碼。這種方法顯然浪費了很多時間,為了解決這個問題人們編寫了各種各樣的庫。但由於編程語言和環境的不同這些庫一般都不能通用,而且用戶在運行程序時還需要這些庫才行,極不方便。DLL的出現就像制定了一個標准一樣,使這些庫有了統一的規范。這樣一來,用不同編程語言的程序員可以方便的使用用別的編程語言編寫的DLL。另外,DLL還有一個突出的特點就是在內存中只裝載一次,這一點可以節省有限的內存,而且可以同時為多個進程服務。

三、便於維護和升級。
細心的朋友可能發現有一些DLL文件是有版本說明的。(查看DLL文件的屬性可以看到,但不是每一個DLL文件都有)這是為了便於維護和升級。舉個例子吧,早期的Win95中有一個BUG那就是在閏年不能正確顯示2月29日這一天。後來,Microsoft發布了一個補丁程序糾正了這個BUG。值得一提的是,我們並沒有重裝Win95,而是用新版本的DLL代替了舊版本的DLL。(具體是哪一個DLL文件筆者一時想不起來了。)另一個常見的例子是驅動程序的升級。例如,著名的DirectX就多次升級,現在已經發展到了6.0版了。更妙的是,當我們試圖安裝較低版本的DLL時,系統會給我們提示,避免人為的操作錯誤。例如我們升級某硬體的驅動程序時,經常碰到Windows提示我們當前安裝的驅動程序比原來的驅動程序舊。

四、比較安全。
這里說的安全也包括很多方面。比如,DLL文件遭受病毒的侵害機率要比普通的EXE文件低很多。另外,由於是動態鏈接的,這給一些從事破壞工作的「高手」們多少帶來了一些反匯編的困難。

第二章 在Delphi中編寫DLL top

注意:在這里筆者假定讀者使用的是Delphi 3或Delphi 4開場白說了那麼多,總該言歸正傳了。編寫DLL其實也不是一件十分困難的事,只是要注意一些事項就夠了。為便於說明,我們先舉一個例子。

library Delphi;

uses
SysUtils,
Classes;

function TestDll(i:integer):integer;stdcall;
begin
Result:=i;
end;

exports
TestDll;

begin
end.

上面的例子是不是很簡單?熟悉Delphi的朋友可以看出以上代碼和一般的Delphi程序的編寫基本是相同的,只是在TestDll函數後多了一個stdcall參數並且用exports語句聲明了TestDll函數。只要編譯上面的代碼,就可以得到一個名為Delphi.dll的動態鏈接庫。現在,讓我們來看看有哪些需要注意的地方。 一、在DLL中編寫的函數或過程都必須加上stdcall調用參數。在Delphi 1或Delphi 2環境下該調用參數是far。從Delphi 3以後將這個參數變為了stdcall,目的是為了使用標準的Win32參數傳遞技術來代替優化的register參數。忘記使用stdcall參數是常見的錯誤,這個錯誤不會影響DLL的編譯和生成,但當調用這個DLL時會發生很嚴重的錯誤,導致操作系統的死鎖。原因是register參數是Delphi的默認參數。

二、所寫的函數和過程應該用exports語句聲明為外部函數。
正如大家看到的,TestDll函數被聲明為一個外部函數。這樣做可以使該函數在外部就能看到,具體方法是單激滑鼠右鍵用「快速查看(Quick View)」功能查看該DLL文件。(如果沒有「快速查看」選項可以從Windows CD上安裝。)TestDll函數會出現在Export Table欄中。另一個很充分的理由是,如果不這樣聲明,我們編寫的函數將不能被調用,這是大家都不願看到的。

三、當使用了長字元串類型的參數、變數時要引用ShareMem。
Delphi中的string類型很強大,我們知道普通的字元串長度最大為256個字元,但Delphi中string類型在默認情況下長度可以達到2G。(對,您沒有看錯,確實是兩兆。)這時,如果您堅持要使用string類型的參數、變數甚至是記錄信息時,就要引用ShareMem單元,而且必須是第一個引用的。既在uses語句後是第一個引用的單元。如下例:
uses
ShareMem,
SysUtils,
Classes;
還有一點,在您的工程文件(*.dpr)中而不是單元文件(*.pas)中也要做同樣的工作,這一點Delphi自帶的幫助文件沒有說清楚,造成了很多誤會。不這樣做的話,您很有可能付出死機的代價。避免使用string類型的方法是將string類型的參數、變數等聲明為Pchar或ShortString(如:s:string[10])類型。同樣的問題會出現在當您使用了動態數組時,解決的方法同上所述。

第三章 在Delphi中靜態調用DLL top

調用一個DLL比寫一個DLL要容易一些。首先給大家介紹的是靜態調用方法,稍後將介紹動態調用方法,並就兩種方法做一個比較。同樣的,我們先舉一個靜態調用的例子。

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
procere Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

//本行以下代碼為我們真正動手寫的代碼

function TestDll(i:integer):integer;stdcall;
external 』Delphi.dll』;

procere TForm1.Button1Click(Sender: TObject);
begin
Edit1.Text:=IntToStr(TestDll(1));
end;

end.

上面的例子中我們在窗體上放置了一個編輯框(Edit)和一個按鈕(Button),並且書寫了很少的代碼來測試我們剛剛編寫的Delphi.dll。大家可以看到我們唯一做的工作是將TestDll函數的說明部分放在了implementation中,並且用external語句指定了Delphi.dll的位置。(本例中調用程序和Delphi.dll在同一個目錄中。)讓人興奮的是,我們自己編寫的TestDll函數很快被Delphi認出來了。您可做這樣一個實驗:輸入「TestDll(」,很快Delphi就會用fly-by提示條提示您應該輸入的參數是什麼,就像我們使用Delphi中定義的其他函數一樣簡單。注意事項有以
下一些:

一、調用參數用stdcall。
和前面提到的一樣,當引用DLL中的函數和過程時也要使用stdcall參數,原因和前面提到的一樣。

二、用external語句指定被調用的DLL文件的路徑和名稱。
正如大家看到的,我們在external語句中指定了所要調用的DLL文件的名稱。沒有寫路徑是因為該DLL文件和調用它的主程序在同一目錄下。如果該DLL文件在C:\,則我們可將上面的引用語句寫為external 』C:\Delphi.dll』。注意文件的後綴.dll必須寫上。

三、不能從DLL中調用全局變數。
如果我們在DLL中聲明了某種全局變數,如:var s:byte 。這樣在DLL中s這個全局變數是可以正常使用的,但s不能被調用程序使用,既s不能作為全局變數傳遞給調用程序。不過在調用程序中聲明的變數可以作為參數傳遞給DLL。

四、被調用的DLL必須存在。
這一點很重要,使用靜態調用方法時要求所調用的DLL文件以及要調用的函數或過程等等必須存在。如果不存在或指定的路徑和文件名不正確的話,運行主程序時系統會提示「啟動程序時出錯」或「找不到*.dll文件」等運行錯誤。

第四章 在Delphi中動態調用DLL top

動態調用DLL相對復雜很多,但非常靈活。為了全面的說明該問題,這次我們舉一個調用由C++編寫的DLL的例子。首先在C++中編譯下面的DLL源程序。

#include

extern 」C」 _declspec(dllexport)
int WINAPI TestC(int i)
{
return i;
}

編譯後生成一個DLL文件,在這里我們稱該文件為Cpp.dll,該DLL中只有一個返回整數類型的函數TestC。為了方便說明,我們仍然引用上面的調用程序,只是將原來的Button1Click過程中的語句用下面的代碼替換掉了。

procere TForm1.Button1Click(Sender: TObject);
type
TIntFunc=function(i:integer):integer;stdcall;
var
Th:Thandle;
Tf:TIntFunc;
Tp:TFarProc;
begin
Th:=LoadLibrary(』Cpp.dll』); {裝載DLL}
if Th>0 then
try
Tp:=GetProcAddress(Th,PChar(』TestC』));
if Tp<>nil
then begin
Tf:=TIntFunc(Tp);
Edit1.Text:=IntToStr(Tf(1)); {調用TestC函數}
end
else
ShowMessage(』TestC函數沒有找到』);
finally
FreeLibrary(Th); {釋放DLL}
end
else
ShowMessage(』Cpp.dll沒有找到』);
end;

大家已經看到了,這種動態調用技術很復雜,但只要修改參數,如修改LoadLibrary(』Cpp.dll』)中的DLL名稱為』Delphi.dll』就可動態更改所調用的DLL。

一、定義所要調用的函數或過程的類型。
在上面的代碼中我們定義了一個TIntFunc類型,這是對應我們將要調用的函數TestC的。在其他調用情況下也要做同樣的定義工作。並且也要加上stdcall調用參數。

二、釋放所調用的DLL。
我們用LoadLibrary動態的調用了一個DLL,但要記住必須在使用完後手動地用FreeLibrary將該DLL釋放掉,否則該DLL將一直佔用內存直到您退出Windows或關機為止。

現在我們來評價一下兩種調用DLL的方法的優缺點。靜態方法實現簡單,易於掌握並且一般來說稍微快一點,也更加安全可靠一些;但是靜態方法不能靈活地在運行時裝卸所需的DLL,而是在主程序開始運行時就裝載指定的DLL直到程序結束時才釋放該DLL,另外只有基於編譯器和鏈接器的系統(如Delphi)才可以使用該方法。動態方法較好地解決了靜態方法中存在的不足,可以方便地訪問DLL中的函數和過程,甚至一些老版本DLL中新添加的函數或過程;但動態方法難以完全掌握,使用時因為不同的函數或過程要定義很多很復雜的類型和調用方法。對於初學者,筆者建議您使用靜態方法,待熟練後再使用動態調用方法。

第五章 使用DLL的實用技巧 top

一、編寫技巧。
1 、為了保證DLL的正確性,可先編寫成普通的應用程序的一部分,調試無誤後再從主程序中分離出來,編譯成DLL。

2 、為了保證DLL的通用性,應該在自己編寫的DLL中杜絕出現可視化控制項的名稱,如:Edit1.Text中的Edit1名稱;或者自定義非Windows定義的類型,如某種記錄。

3 、為便於調試,每個函數和過程應該盡可能短小精悍,並配合具體詳細的注釋。

4 、應多利用try-finally來處理可能出現的錯誤和異常,注意這時要引用SysUtils單元。

5 、盡可能少引用單元以減小DLL的大小,特別是不要引用可視化單元,如Dialogs單元。例如一般情況下,我們可以不引用Classes單元,這樣可使編譯後的DLL減小大約16Kb。

二、調用技巧。
1 、在用靜態方法時,可以給被調用的函數或過程更名。在前面提到的C++編寫的DLL例子中,如果去掉extern 」C」語句,C++會編譯出一些奇怪的函數名,原來的TestC函數會被命名為@TestC$s等等可笑的怪名字,這是由於C++採用了C++ name mangling技術。這個函數名在Delphi中是非法的,我們可以這樣解決這個問題:
改寫引用函數為
function TestC(i:integer):integer;stdcall;
external 』Cpp.dll』;name 』@TestC$s』;
其中name的作用就是重命名。

2 、可把我們編寫的DLL放到Windows目錄下或者Windows\system目錄下。這樣做可以在external語句中或LoadLibrary語句中不寫路徑而只寫DLL的名稱。但這樣做有些不妥,這兩個目錄下有大量重要的系統DLL,如果您編的DLL與它們重名的話其後果簡直不堪設想,況且您的編程技術還不至於達到將自己編寫的DLL放到系統目錄中的地步吧!

三、調試技巧。
1 、我們知道DLL在編寫時是不能運行和單步調試的。有一個辦法可以,那就是在Run|parameters菜單中設置一個宿主程序。在Local頁的Host Application欄中添上宿主程序的名字就可進行單步調試、斷點觀察和運行了。

2 、添加DLL的版本信息。開場白中提到了版本信息對於DLL是很重要的,如果包含了版本信息,DLL的大小會增加2Kb。增加這么一點空間是值得的。很不幸我們如果直接使用Project|options菜單中Version選項是不行的,這一點Delphi的幫助文件中沒有提到,經筆者研究發現,只要加一行代碼就可以了。如下例:

library Delphi;

uses
SysUtils,
Classes;

{$R *.RES}
//注意,上面這行代碼必須加在這個位置

function TestDll(i:integer):integer;stdcall;
begin
Result:=i;
end;

exports
TestDll;

begin
end.

3 、為了避免與別的DLL重名,在給自己編寫的DLL起名字的時候最好採用字元數字和下劃線混合的方式。如:jl_try16.dll。

4 、如果您原來在Delphi 1或Delphi 2中已經編譯了某些DLL的話,您原來編譯的DLL是16位的。只要將源代碼在新的Delphi 3或Delphi 4環境下重新編譯,就可以得到32位的DLL了。

[後記]:除了上面介紹的DLL最常用的使用方法外,DLL還可以用於做資源的載體。例如,在Windows中更改圖標就是使用的DLL中的資源。另外,熟練掌握了DLL的設計技術,對使用更為高級的OLE、COM以及ActiveX編程都有很多益處。

9. 如何編譯一個 dll文件

創建DLL工程
這里,我們為了簡要說明DLL的原理,我們決定使用最簡單的編譯環境VC6.0,如下圖,我們先建立一個新的Win32 Dynamic-Link Library工程,名稱為「MyDLL」,在Visual Studio中,你也可以通過建立Win32控制台程序,然後在「應用程序類型」中選擇「DLL」選項,

點擊確定,選擇「一個空的DLL工程」,確定,完成即可。

一個簡單的dll
在第一步我們建立的工程中建立一個源碼文件」dllmain.cpp「,在「dllmain.cpp」中,鍵入如下代碼

[cpp] view plain
#include <Windows.h>
#include <stdio.h>

BOOL APIENTRY DllMain(HMODULE hMole, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
printf("DLL_PROCESS_ATTACH\n");
break;
case DLL_THREAD_ATTACH:
printf("DLL_THREAD_ATTACH\n");
break;
case DLL_THREAD_DETACH:
printf("DLL_THREAD_DETACH\n");
break;
case DLL_PROCESS_DETACH:
printf("DLL_PROCESS_DETACH\n");
break;
}
return TRUE;
}
之後,我們直接編譯,即可以在Debug文件夾下,找到我們生成的dll文件,「MyDLL.dll」,注意,代碼裡面的printf語句,並不是必須的,只是我們用於測試程序時使用。而DllMain函數,是dll的進入/退出函數。

實際上,讓線程調用DLL的方式有兩種,分別是隱式鏈接和顯式鏈接,其目的均是將DLL的文件映像映射進線程的進程的地址空間。我們這里只大概提一下,不做深入研究,如果感興趣,可以去看《Window高級編程指南》的第12章內容。
隱式鏈接調用
隱士地鏈接是將DLL的文件影響映射到進程的地址空間中最常用的方法。當鏈接一個應用程序時,必須制定要鏈接的一組LIB文件。每個LIB文件中包含了DLL文件允許應用程序(或另一個DLL)調用的函數的列表。當鏈接器看到應用程序調用了某個DLL的LIB文件中給出的函數時,它就在生成的EXE文件映像中加入了信息,指出了包含函數的DLL文件的名稱。當操作系統載入EXE文件時,系統查看EXE文件映像的內容來看要裝入哪些DLL,而後試圖將需要的DLL文件映像映射到進程的地址空間中。當尋找DLL時,系統在系列位置查找文件映像。

1.包含EXE映像文件的目錄
2.進程的當前目錄
3.Windows系統的目錄
4.Windows目錄
5.列在PATH環境變數中的目錄

這種方法,一般都是在程序鏈接時控制,反映在鏈接器的配置上,網上大多數講的各種庫的配置,比如OPENGL或者OPENCV等,都是用的這種方法

顯式鏈接調用
這里我們只提到兩種函數,一種是載入函數
[cpp] view plain
HINSTANCE LoadLibrary(LPCTSTR lpszLibFile);

HINSTANCE LoadLibraryEx(LPCSTR lpszLibFile,HANDLE hFile,DWORD dwFlags);
返回值HINSTANCE值指出了文件映像映射的虛擬內存地址。如果DLL不能被映進程的地址空間,函數就返回NULL。你可以使用類似於

[cpp] view plain
LoadLibrary("MyDLL")
或者

[cpp] view plain
LoadLibrary("MyDLL.dll")
的方式進行調用,不帶後綴和帶後綴在搜索策略上有區別,這里不再詳解。

顯式釋放DLL

在顯式載入DLL後,在任意時刻可以調用FreeLibrary函數來顯式地從進程的地址空間中解除該文件的映像。
[cpp] view plain
BOOL FreeLibrary(HINSTANCE hinstDll);
這里,在同一個進程中調用同一個DLL時,實際上還牽涉到一個計數的問題。這里也不在詳解。
線程可以調用GetMoleHandle函數:

[cpp] view plain
GetMoleHandle(LPCTSTR lpszMoleName);
來判斷一個DLL是否被映射進進程的地址空間。例如,下面的代碼判斷MyDLL.dll是否已被映射到進程的地址空間,如果沒有,則裝入它:

[cpp] view plain
HINSTANCE hinstDll;
hinstDll = GetMoleHandle("MyDLL");
if (hinstDll == NULL){
hinstDll = LoadLibrary("MyDLL");
}
實際上,還有一些函數,比如 GetMoleFileName用來獲取DLL的全路徑名稱,FreeLibraryAndExitThread來減少DLL的使用計數並退出線程。具體內容還是參見《Window高級編程指南》的第12章內容,此文中不適合講太多的內容以至於讀者不能一下子接受。

DLL的進入與退出函數

說到這里,實際上只是講了幾個常用的函數,這一個小節才是重點。
在上面,我們看到的MyDLL的例子中,有一個DllMain函數,這就是所謂的進入/退出函數。系統在不同的時候調用此函數。這些調用主要提供信息,常常被DLL用來執行進程級或線程級的初始化和清理工作。如果你的DLL不需要這些通知,就不必再你的DLL源代碼中實現此函數,例如,如果你創建的DLL只含有資源,就不必實現該函數。但如果有,則必須像我們上面的格式。
DllMain函數中的ul_reason_for_call參數指出了為什麼調用該函數。該參數有4個可能值: DLL_PROCESS_ATTACH、DLL_THREAD_ATTACH、DLL_THREAD_DETACH、DLL_PROCESS_DETACH。
其中,DLL_PROCESS_ATTACH是在一個DLL首次被映射到進程的地址空間時,系統調用它的DllMain函數,傳遞的ul_reason_for_call參數為DLL_PROCESS_ATTACH。這只有在首次映射時發生。如果一個線程後來為已經映射進來的DLL調用LoadLibrary或LoadLibraryEx,操作系統只會增加DLL的計數,它不會再用DLL_PROCESS_ATTACH調用DLL的DllMain函數。
而DLL_PROCESS_DETACH是在DLL被從進程的地址空間解除映射時,系統調用它的DllMain函數,傳遞的ul_reason_for_call值為DLL_PROCESS_DETACH。我們需要注意的是,當用DLL_PROCESS_ATTACH調用DLL的DllMain函數時,如果返回FALSE,說明初始化不成功,系統仍會用DLL_PROCESS_DETACH調用DLL的DllMain。因此,必須確保沒有清理那些沒有成功初始化的東西。
DLL_THREAD_ATTACH:當進程中創建一個線程時,系統察看當前映射到進程的地址空間中的所有DLL文件映像,並用值DLL_THREAD_ATTACH調用所有的這些DLL的DllMain函數。該通知告訴所有的DLL去執行線程級的初始化。注意,當映射一個新的DLL時,進程中已有的幾個線程在運行,系統不會為已經運行的線程用值DLL_THREAD_ATTACH調用DLL的DllMain函數。
而DLL_THREAD_DETACH,如果線程調用ExitThread來終結(如果讓線程函數返回而不是調用ExitThread,系統會自動調用ExitThread),系統察看當前映射到進程空間的所有DLL文件映像,並用值DLL_THREAD_DETACH來調用所有的DLL的DllMain函數。該通知告訴所有的DLL去執行線程級的清理工作。
這里,我們需要注意的是,如果線程的終結是因為系統中的一個線程調用了TerminateThread,系統就不會再使用DLL_THREAD_DETACH來調用DLL和DllMain函數。這與TerminateProcess一樣,不再萬不得已時,不要使用。
下面,我們貼出《Window高級編程指南》中的兩個圖來說明上述四種參數的調用情況。

好的,介紹了以上的情況,下面,我們來繼續實踐,這次,建立一個新的空的win32控制台工程TestDLL,不再多說,代碼如下:

[cpp] view plain
#include <iostream>
#include <Windows.h>
using namespace std;

DWORD WINAPI someFunction(LPVOID lpParam)
{
cout << "enter someFunction!" << endl;
Sleep(1000);
cout << "This is someFunction!" << endl;
Sleep(1000);
cout << "exit someFunction!" << endl;
return 0;
}

int main()
{
HINSTANCE hinstance = LoadLibrary("MyDLL");
if(hinstance!=NULL)
{
cout << "Load successfully!" << endl;
}else {
cout << "Load failed" << endl;
}
HANDLE hThread;
DWORD dwThreadId;

cout << "createThread before " << endl;
hThread = CreateThread(NULL,0,someFunction,NULL,0,&dwThreadId);
cout << "createThread after " << endl;
cout << endl;

Sleep(3000);

cout << "waitForSingleObject before " << endl;
WaitForSingleObject(hThread,INFINITE);
cout << "WaitForSingleObject after " << endl;
cout << endl;

FreeLibrary(hinstance);
return 0;
}

代碼很好理解,但是前提是,你必須對線程有一定的概念。另外,注意,我們上面編譯的獲得的「MyDLL.dll"必須拷貝到能夠讓我們這個工程找到的地方,也就是上面我們提到的搜索路徑中的一個地方。
這里,我們先貼結果,當然,這只是在我機器上其中某次運行結果。

有了上面我們介紹的知識,這個就不是很難理解,主進程在調用LoadLibrary時,用DLL_PROCESS_ATTACH調用了DllMain函數,而線程創建時,用DLL_THREAD_ATTACH調用了DllMain函數,而由於主線程和子線程並行的原因,可能輸出的時候會有打斷。但是,這樣反而能讓我們更清楚的理解程序。

10. 為什麼我下載的易語言源碼編譯出來後是DLL文件

載的易語言源碼,源碼都是.e的後綴
但是你的這個源碼,人家做的時候就是弄的.DLL動態鏈接庫,所以編譯後就是DLL。
這個應該是G吧??需要注入的

閱讀全文

與dll文件是編譯後的嗎相關的資料

熱點內容
樂高機器人nxt編程軟體 瀏覽:583
linuxx264編譯 瀏覽:343
華夏銀行網銀盾用什麼app 瀏覽:583
單片機棧區 瀏覽:64
直流馬達如何連接5v單片機 瀏覽:261
後綴為win的文件怎麼解壓 瀏覽:802
壓縮包解壓後為什麼一張白紙 瀏覽:585
伺服器和雲盒子 瀏覽:172
python畫cad電氣圖 瀏覽:419
三菱plcfx3sa編程電纜 瀏覽:314
山西視頻加密防盜 瀏覽:839
華為mml命令查看用戶量 瀏覽:907
場論朗道pdf 瀏覽:373
如何使用qtquick編譯器 瀏覽:50
山西高配伺服器雲伺服器 瀏覽:744
為什麼編譯按f9沒反應 瀏覽:122
購物app都適合買什麼東西 瀏覽:277
savetxt函數python 瀏覽:577
編譯器小端改大端 瀏覽:642
華為安卓哪些文件夾能刪除 瀏覽:406