小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

VC++2008用空工程創(chuàng)建DLL

 昵稱y8F2YCzG 2015-04-24
一、創(chuàng)建 DLL 工程項(xiàng)目:
 1)點(diǎn)擊菜單[File] -> [New] -> [Project...] 彈出 “New Project” 對話框;
 2)在左側(cè) [Project types:] 樹形框中展開 [Visual C++] 選擇 [Win32];
 3)在右側(cè) [Templates:] 視圖框中選擇 [Win32 Project];
 4)在 [Name:] 對應(yīng)的文本框中填寫好項(xiàng)目名稱;
 5)在 [Location:] 對應(yīng)的文本框中選好項(xiàng)目位置;
 6)點(diǎn)擊 [OK] 按鈕,彈出 “Win32 Application Wizard - 你起的項(xiàng)目名稱” 對話框;
 7)點(diǎn)擊左側(cè)的 [Application Settings] 或 點(diǎn)擊 [Next >] 進(jìn)入 “Application Settings” 選項(xiàng)頁;
 8)在 [Application type:] 中選擇 “DLL”;
 9)在 [Additional options:] 中選擇 “Empty project”;
10)最后點(diǎn)擊 [Finish] 按鈕。


二、編寫 DLL 導(dǎo)出函數(shù)頭文件(exampledll.h):
#ifdef DLL_EXPORTS
#define DLL_API_INT _declspec(dllexport) int __stdcall
#else
#define DLL_API_INT _declspec(dllimport) int __stdcall
#endif


#ifdef __cplusplus
// extern "C" 是 C++ 的關(guān)鍵字

extern "C"
{
#endif


DLL_API_INT sum( int a, int b );
DLL_API_INT sub( int a, int b );

#ifdef __cplusplus
}
#endif



注:
1. __declspec(dllexport) 聲明函數(shù)為 DLL 的導(dǎo)出函數(shù),
   它就是為了省掉在 *.def 文件中手工定義導(dǎo)出哪些函數(shù)的一個(gè)方法,
   如果你的 DLL 里全是 C++ 的類的話,你無法在 *.def 里指定導(dǎo)出的函數(shù),
   只能用 __declspec(dllexport) 導(dǎo)出類;

; 舉例 exampledll.def 文件內(nèi)容
LIBRARY exampledll
EXPORTS
sum @ 1
sub @ 2
var DATA

.def文件的規(guī)則為:
注:需要在工程屬性中指定該*.def文件,位置:
[Configuration Properties] -> [Linker] -> [Input] -> "Module Definition File"
不用 *.def 文件導(dǎo)出函數(shù)的話,函數(shù)名將是按編譯器的命名規(guī)則導(dǎo)出。

1)LIBRARY 關(guān)鍵字后跟該 def 文件對應(yīng)的 DLL 工程名;
2)EXPORTS 關(guān)鍵字獨(dú)占一行,下面每行列出要導(dǎo)出函數(shù)或變量的名稱;
  可以在要導(dǎo)出的函數(shù)名后加 @ 數(shù)字,即為要導(dǎo)出函數(shù)排序,在動(dòng)態(tài)加載導(dǎo)出函數(shù)時(shí),此序號有用;
  若要導(dǎo)出某全局變量,要有如下格式:
  變量名 CONSTANT <-- 過時(shí)的方法,變量名后跟 CONSTANT 關(guān)鍵字
 
  變量名 DATA   <-- VC++提示的新方法,變量名后跟 DATA 關(guān)鍵字
  注意:
  用 extern 聲明導(dǎo)入的并不是 DLL 中全局變量本身,而是其地址,
  應(yīng)用程序必須先通過類型強(qiáng)制轉(zhuǎn)換指針,再間接取/賦值來使用 DLL 中的全局變量,如:
  extern int var;
  *(int*)var = 1;
  通過 _declspec(dllimport) 方式導(dǎo)入的就是DLL中全局變量本身而不再是其地址了,
  建議盡可能的情使用這種方式,如:
  extern int _declspec(dllimport) var;
  var = 1;
3)分號(;) 為行注釋符且注釋不能與語句共享一行,要獨(dú)占一行,以分號開頭。

2. __declspec(dllimport) 聲明函數(shù)為 DLL 的導(dǎo)入函數(shù),
   不使用 __declspec(dllimport) 也能正確編譯代碼,
   但使用 __declspec(dllimport) 使編譯器可以生成更好的代碼,
   編譯器之所以能夠生成更好的代碼,是因?yàn)樗梢源_定函數(shù)是否存在于 DLL 中,
   這使得編譯器可以生成跳過間接尋址級別的代碼,而這些代碼通常會(huì)出現(xiàn)在跨 DLL 邊界的函數(shù)調(diào)用中。
   但是必須使用 __declspec(dllimport) 才能導(dǎo)入 DLL 中使用的變量,
   原來 __declspec(dllimport) 是為了更好的處理類中的靜態(tài)成員變量的,
   如果沒有靜態(tài)成員變量,那么這個(gè) __declspec(dllimport) 無所謂;

3. 函數(shù)的調(diào)用方式更改:
   方法一:
   1)右擊 "Solution Explorer" 中的項(xiàng)目名;
   2)選擇 "Properties";
   3)在彈出的對話框左側(cè)樹形框中選擇 [Configuration Properties] -> [C/C++] -> [Advanced];
   4)在彈出的對話框右側(cè)柵欄框中修改 "Calling Convention" 項(xiàng)對應(yīng)值。
   方法二:
   microsoft 的 VC 默認(rèn)的是 __cdecl 方式,而 windows API 則是 __stdcall ,
   如果用 VC 開發(fā) dll 給其他語言用,則應(yīng)該指定 __stdcall 方式。
   如果是 __cdecl   方式的函數(shù),則函數(shù)本身則不需要關(guān)心保存參數(shù)的堆棧的清除,
   如果是 __stdcall 方式的函數(shù),則一定要在函數(shù)退出前恢復(fù)堆棧。

   1)__cdecl 所謂的 C 調(diào)用規(guī)則。按從右至左的順序壓參數(shù)入棧,由調(diào)用者把參數(shù)彈出棧。
     切記:對于傳送參數(shù)的內(nèi)存棧是由調(diào)用者來維護(hù)的。
        返回值在 EAX 中因此,對于象 printf 這樣變參數(shù)的函數(shù)必須用這種規(guī)則。
        編譯器在編譯的時(shí)候?qū)@種調(diào)用規(guī)則的函數(shù)生成修飾名的時(shí)候,
        僅在輸出函數(shù)名前加上一個(gè)下劃線前綴,格式為 _functionname 。 

   2)__stdcall 按從右至左的順序壓參數(shù)入棧,由被調(diào)用者把參數(shù)彈出棧。
     __stdcall 是 Pascal 程序的缺省調(diào)用方式,
     通常用于 Win32 Api 中,切記:函數(shù)自己在退出時(shí)清空堆棧,返回值在EAX中。
     __stdcall 調(diào)用約定在輸出函數(shù)名前加上一個(gè)下劃線前綴,后面加上一個(gè) @ 符號和其參數(shù)的字節(jié)數(shù),
     格式為 _functionname@number 。
     如函數(shù) int func(int a, double b) 的修飾名是 _func@12 。

   3)__fastcall 調(diào)用的主要特點(diǎn)就是快,
     因?yàn)樗峭ㄟ^寄存器來傳送參數(shù)的,
     實(shí)際上,它用 ECX 和 EDX 傳送前兩個(gè)雙字(DWORD)或更小的參數(shù),
     剩下的參數(shù)仍舊自右向左壓棧傳送,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的內(nèi)存棧。
     __fastcall 調(diào)用約定在輸出函數(shù)名前加上一個(gè) @ 符號,后面也是一個(gè) @ 符號和其參數(shù)的字節(jié)數(shù),
     格式為 @functionname@number 。
     這個(gè)和 __stdcall 很象,唯一差別就是頭兩個(gè)參數(shù)通過寄存器傳送。
     注意通過寄存器傳送的兩個(gè)參數(shù)是從左向右的,即第一個(gè)參數(shù)進(jìn)ECX,第2個(gè)進(jìn)EDX,
     其他參數(shù)是從右向左的入棧。返回仍然通過EAX。

   4)__pascal 這種規(guī)則從左向右傳遞參數(shù),通過 EAX 返回,堆棧由被調(diào)用者清除。

   5)__thiscall 僅僅應(yīng)用于 C++ 成員函數(shù)。
     this 指針存放于 CX 寄存器,參數(shù)從右到左壓。thiscall不是關(guān)鍵詞,因此不能被程序員指定。

   修飾符的書寫順序如下:
   extern "C" _declspec(dllexport) int __stdcall sum(int a, int b);
   typedef int (__cdecl *FunPointer)(int a, int b);

4.如果要對編譯器提示使用 C 的方式來處理函數(shù)的話,那么就要使用 extern "C" 來說明。

三、編寫 DLL 導(dǎo)出函數(shù)實(shí)現(xiàn)文件(exampledll.c):
#ifndef DLL_EXPORTS
#define DLL_EXPORTS
#endif

#include "windows.h"  
#include "exampledll.h"

 
#pragma comment(linker,"/section:shared,rws")  
#pragma data_seg("shared")
int var = 0;  
#pragma data_seg()


extern "C" BOOL __stdcall 
DllMain( HINSTANCE hInstance, 
         DWORD     dwReason, 
         LPVOID    lpReserved)
{  
    switch( dwReason )
    {
        case DLL_PROCESS_ATTACH:
            return TRUE;
        case DLL_PROCESS_DETACH:
            return TRUE;
        case DLL_THREAD_ATTACH:
            return TRUE;
        case DLL_THREAD_DETACH:
            return TRUE;
        default:
            return TRUE;
    }
}  

DLL_API_INT sum( int a, int b )
{
    return a + b;
}

DLL_API_INT sub( int a, int b )
{
    return a - b;
}

四、編譯生成 DLL 即可!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多