DLL輸入和輸出函數—dllinport與dllexport


Microsoft特殊處

dllimport和dllexport存儲類修飾符是C語言的Microsoft特殊處擴充。這些修飾顯式定義了DLL的客戶界面(可執行的文件或另外的DLL)。說明為dllexport的函數消除了一個模塊定義(.DLL)文件的需要。你可以為數據和對象使用dllimport和dllexport修飾符。

dllimport和dllexport存儲類修飾符必須與擴充的屬性語法關鍵字__declspec一起使用,下面是這樣的例子:

#define DllImport __declspec(dllimport)

#define DllExport __declspec(dllexport)

DllExport void func();

Dllexport int i = 10;

DllExport int j;

DllExport int n;

有關擴充的存儲類修飾符的語法的指定信息,參見第3章“說明和類型”中的“擴充的存儲類型屬性”。

Microsoft特殊處結束

定義和說明

Microsoft特殊處

DLL界面指的是系統中某個程序中輸出的所有已知項(函數和數據);也就是所有說明為dllimport或dllexport的所有項。包括在DLL界面中的所有說明必須指定為dllimport或dllexport屬性。但該定義只能指定dllexport屬性。例如,如下函數定義生成一個編譯器錯誤:

#define DLLImport __declspec(dllimport)

#define DLLExport __declspec(dllexport)

DLLImport int func()/*錯誤:在定義中禁止dllimport*/

{
return 1;
}

下面代碼也產生一個錯誤:

#define DllImport __declspec(dllimport)

#define DllExport __declspec(dllexport)

DllImport int i=10; /*錯誤:這是一個定義*/

但如下是正確的語法:

#define DllImport __declspec(dllimport)

#define DllExport __declspec(dllexport)

DllExport int i=10; /*正確:這是一個輸出定義*/

dllexport的使用隱含一個定義,而dllimport隱含一個說明。你必須對dllexport使用extern關鍵字強制為一個說明;否則,隱含是一個定義。

#define DllImport __declspec(dllimport)

#define DllExport __declspec(dllexport)

extern DllImport int k; /*這是正確的並隱含一個說明*/

Dllimport int j;

Microsoft特殊處結束

用dllexport和dllimport定義聯編函數

Microsoft特殊處

你可以用dllexport屬性定義一個聯編函數,在這種情況下,該函數總是被實例化和被輸出,無論程序中的任何模塊引用該函數。該函數假定是被另一程序輸入。

你也可以用dllimport屬性說明一個函數為聯編函數,在這種情況下,該函數可以被伸展(從屬於/Ob(聯編)編譯器選項規格)但不能被實例化。在特殊情況中,如果一個聯編輸入的函數的地址被占用,該函數的地址保留在返回的DLL中。這個行為和占用一個非聯編輸入的函數的地址相同。在聯編函數中的靜態局部數據和字符串在DLL和象在單個程序中似的客戶(也就是,一個沒有DLL界面的可執行文件)之間維護相同的標識符。

在進行提供輸入的聯編函數的練習時要小心,例如,如果你修改DLL,不要假設該客戶使用該DLL的改變的版本。為了保證你加載適當的DLL版本,重新建立該DLL的客戶。

Microsoft特殊處結束

dllimport/dllexport的規則和限制

Microsoft特殊處

* 如果你說明一個函數沒有dllimport或dllexport屬性,該函數不認為是DLL界面的部分。因此,該函數的定義必須出現在該模塊中或相同程序的另一個模塊中。為了使該函數成為DLL界面部分,必須在其它模塊中以dllexport說明該函數的定義;否則,在建立客戶時產生一個鏈接器錯誤。

* 如果你的程序的單個模塊包含相同函數的dllimport和dllexport說明,那么dllexport屬性的優先級比dllimport屬性的優先級高。但編譯器產生一個警告。例如:

#define DLLimport __declspec(dllimport)

#define DLLexport __declspec(dllexport)

DllImport void func1(void); DllExport void func1(void);/*警告:dllexport更優先*/

* 你不能用一個以dllimport屬性說明的數據對象的地址初始化一個靜態數據指針。

例如,如下代碼產生一個錯誤:#define DllImport __declspec(dllimport)#define DllExport __declspec(dllexport) DllImport int i ; . . . int *pi=&i; /* 錯誤 */ void func2() { static int *pi=&i; /* 錯誤 */ }

* 用一個dllimport說明的函數的地址初始化一個靜態函數指針,設置該指針為該DLL輸入形實替換程序(一個轉換控制到該函數的代碼塊)而不是該函數的地址。如下賦值不產生錯誤消息:

#define DllImport __declspec(dllimport)

#define DllExport __declspec(dllexport)

DllImport void func1(void)

. . . static void (*pf)(void)=&func1;/* 沒有錯誤 */

void func2()

{

static void (*pf)(void)=&func1;/* 沒有錯誤 */

}

* 因為在一個對象的說明中包括dllexport屬性的程序必須提供這個對象的定義,你可以用一個dllexport函數的地址初始化一個全局或局部靜態函數指針。類似地,你可以用一個dllexport數據對象的地址初始化一個全局或局部靜態數據指針。例如:

#define DllImport __declspec(dllimport)

#define DllExport __declspec(dllexport)

DllImport void func1(void);

DllImport int i;

DllExport void func1(void);

DllExport int i;

. . .

int *pi=&i; /* 正確 */

static void(*pf)(void) = &func1;

/* 正確 */

void func2()
{
static int *pi=i; /* 正確 */
static void (*pf)(void) = &func1; /* 正確 */
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM