為什麼要使用DEF檔案?

2021-04-08 13:31:50 字數 4890 閱讀 7410

無論使用

c語

言或者c++語言來

編寫

動態庫,其

編譯器都會

為每個函式甚至

變數生成乙個

對應的修

飾名(我是這樣翻

譯的。原文是

the decorated names),連

接器將編譯

後的目標**連

接成dll,其輸

出函式名或

變數名依舊是

編譯後的修

飾名。並且修

飾名是與

編譯器相

關的,也就是

說你的源程式是

c,生成的修

飾名是乙個

樣子;如果你的源程式是

c++,

則生成的修

飾名是另一

種樣子。(關於修

飾名的

討論,我將放在乙個

單獨的章

節進行,敬

請等待。糧草未

動,廣告先行。真是的

....

)而我們的應

用習慣

是直接使用函式名,而非修

飾名,我們在用

api時

一直就是如此。那麼,

問題就來了,比如你在vb6

中使用vc6寫的

動態庫:你先在vb6

中使用函式名來描述你要

呼叫的函式,然後寫好呼叫代

碼,接下來執行,

你的vb6這時

會告訴

你,它在

動態庫中找不到你

剛剛描述

過的函式的入口點,你的程式拒

絕執行了。怎

麼辦?解決

問題的方法至少有兩種:

1、修改你的vb6

**

中對動態庫輸

出函式的描述部分,在別名

欄新增

動態庫輸

出函式的修飾名。

2、修改你的

動態庫,新增乙個

def檔案,並使用

def檔案的

exports項來

輸出你的

動態庫函式(在其下

簡單地列出你要

輸出的函式名即可)。雖然,

這樣一來

問題是解決了(

還沒有解決?可能

嗎?有可能啦。但

這裡先停一下,隨後再

說。),但我

們有必要將

該問題進

一步討論

下去。我們寫

動態庫的目的大多是想讓我

們的

動態庫不侷限於某一種程式設計

語言,是

為了更加廣泛地被

應用,我是喜歡用

vb寫介面,而用

vc來完成更重要的工作,如對資料

進行分析、

訪問硬體埠等,而且

vc寫好的

動態庫很少再改動,

vb寫的介面倒是一改再改。

說這麼多,目的只有乙個,寫

動態庫要著眼於「大局

」,要一切符合「標

準」。什麼

是大局?大局就是走可持

續發展的道路,就是

復用(好象是在做政治

報告)。什麼是

標準呢?就是符合

api的

標準(也就是使用

def檔案

輸出函式,就象微軟

的mfc

動態庫)。其實

,使用def

檔案來輸

出函式的乙個最主要目的就是:將

編譯器生成的函式修

飾名去掉,用更加自然的、容易理解的、容易

記憶的名字,而不是修飾名來

輸出函式。

這裡的名字可以不是函式名,

這時須使用

def檔案的

name

格式。但由於

習慣,大多情況下,只使用函式名,因

為這樣最

簡單省事。是否存在

偷懶的嫌疑?我的理解

,不管是

羅列函式名,

還是其它

輸出名,其本

質上是一

樣的,即都是使用了定

義檔案的

name

格式。直接

羅列函式名,就相當於

「函式名

」=「函式修飾名

」,只是可以忽略等號後面的部分,而

聯結器會自

動完成函式入口的匹配和

設定工作。而一旦決定使用非函

數名的其它名字

輸出函式,則必

須書寫完整的格式,即「函式

輸出名

」=「要

輸出的函式修飾名

」,

這裡等號後面的部分必

須書寫正確,否則,

連線

時就通不過了。

舉個例子:假

設動態庫

中乙個函式描述如下,

int winapi testadd(int a,int b)

其def

檔案的exports

段描述如下,

exports

testadd

add=?testadd@@yghhh@z這裡

testadd

和add

實際上指向同乙個入口。如果在

vb程式中調

用testadd

和add,其結

果是一樣

的。二、為什

麼要使用

winapi

巨集?看看上面的

舉例,在函式前加了乙個

winapi巨集。這

一點很重要,它直接

關係著函式輸出什

麼樣子的修

飾名,使用

winapi

巨集的testadd

函式,對應的輸

出修飾

名就是「?testadd@@yghhh@z」。為

什麼

要使用winapi

呢?這牽涉

到動態庫

的另乙個特徵,呼叫

協議(

calling convention

)。如果沒有一定的協議,

動態庫的

呼叫是不可想象的。一般常用的

動態庫呼叫協議

有:__cdecl

__stdcall

__fastcall這些

協議各有各的長處,

這裡

暫不一一描述

。上面在

談到解決

vb程式呼叫

vc寫的

動態庫時

,曾列舉兩種

解決方法,但並不一定可以

實現,它

還取決於所使用的呼叫

協議。

vb所遵循的是

pascal

協議,如果在

動態庫中沒有使用相應的

協議,則vb

程式執行時

就會報告「

呼叫

協議錯」

。而pascal協議在

vc6

中已被廢

棄,取而代之的是

__stdcall,即標

準呼叫協議

,這

也是大多32位

程式設計

語言支援的一種通用

協議。在

windows.h中

winapi

也是被定

義為__stdcall。這

裡提議

使用winapi

的理由也就在

這,它能

夠表達出更加多的資訊

----這樣定

義的

輸出函式(的呼叫

協議)和

windows

api函式(的呼叫

協議)一樣。

其它一些使用

winapi

巨集的理由:你只要在所定

義的函式前加上該

巨集,就不必要在每次

連線

時再去理會各種與

呼叫協議相

關的

設定。況且,你可能並不需要將所有定

義的函式都輸出,

為了提高

執行速度,你可能會將沒有

輸出的函式使用

__fastcall來定義

,為

了使用變

參,你可能使用

__cdecl來定義

某些非輸

出函式,或者諸

如此類

的理由......

需要提醒的是,vc默

認的呼叫

協議是

__cdecl

。如果你在沒有修改呼叫

協議的情況下,直接使用

def檔案

輸出函式,

編譯連線都不會出

錯,但是vb調

用的時

候肯定出

錯。而如果使用了

winapi

巨集,你不必再去理會這些。

編譯器自動使用

winapi的定義

替代整合

環境裡的相

關設定,

這裡函式前的說明

優先

級最高。回過頭

來再看上面有

關輸出函式的修飾名的

討論,上面提到修飾名與

語言有

關,另外,它還與

呼叫協議有

關。如果需要使用非函式名的名字用來

輸出,你必

須清楚你使用的呼叫

協議及語言

種類,也就是你必

須清楚修

飾名的生成

規則,或者你採用一些技巧,

讓dumpbin.exe

工具來幫忙。

三、總結一句話

,如果想建立自己的標準

api動態庫,建議

使用winapi

描述你要

輸出的函式,然後使用定義檔案

輸出它

ogg為什麼需要def檔案

在 goldengate企業級運維實戰 一書中提到用defgen來生成def檔案為rep程序使用。原話如下 當源庫與目標庫型別不一樣或者源端的表與目標端的表結構不相同時,資料定義檔案是必須有的。goldengate企業級運維實戰 page 75 這句話的潛在含義是,如果你的源端和目標端的表是結構相同...

為什麼要使用blog

有哥們問我,你為什麼使用blog?我總結了一下,覺得有如下幾個原因。1對自己的督促 有了blog,就會經常記得寫點東西 就會經常翻翻網上的新文章,了解一下新技術,不至於迷失在忙碌的生活中 如果把自己的所感所想所學寫出了,自己對自己也會有個概念,不至於迷迷糊糊 還有,畢竟是掛在網上的文字,心中難免擔心...

為什麼要使用XML

xml 代表擴充套件標記語言 extensible markup language 是由 world wide web consortium w 3c 的 xml工作組定義的。這個工作組是這樣描述該語言的 擴充套件標記語言 xml 是 sgml 的子集,其目標是允許普通的 sgml 在web 上以目...