VC環境下DLL介面申明的三種方式

2021-06-22 14:32:54 字數 3637 閱讀 9408

本文將介紹三種提供dll介面的方式(對於如何編寫dll內部的**不做介紹),由於筆者工作時間不長,難免有疏漏的之處,還請各位大俠不吝賜教,謝謝!

在dll中寫好介面的實現**後,然後提供乙個申明介面的標頭檔案供呼叫者使用,我想一般都會這樣寫:

#ifdef__dllname_xx

#define_xx_loaddllextern "c" _declspec(dllexport)

#else       //__dllname_xx

#define_xx_loaddllextern "c" _declspec(dllimport)

#endif     //__dllname_xx

// 主要給呼叫該dll的模組使用,應採用自己的命名規則,避免與其它的dll重名

const thar stryourdllname = _t("***.dll"); // dll的名稱

_xx_loaddllbool inte***cea(lpctstr/*[in]*/);

typedef  bool (*lp inte***cea)(lpctstr/*[in]*/);

//其它的介面宣告

定義巨集__dllname_xx的作用

如果我們在dll的工程設定中新增了__dllname_xx的定義,這樣dll的工程由於定義了__dllname_xx,則_xx_loaddll的值為extern "c" _declspec(dllexport),即介面_xx_loaddll  bool inte***cea(lpctstr/*[in]*/);將被展開為extern "c" _declspec(dllexport)  bool inte***cea(lpctstr/*[in]*/);

它正好表示為乙個「匯出函式」,而呼叫該dll的工程由於沒有定義__dllname_xx,則_xx_loaddll的值為extern "c" _declspec(dllimport),即在外部該介面將被展開為

extern "c" _declspec(dllimport)  bool inte***cea(lpctstr/*[in]*/);

而它表示該介面為乙個「匯入介面」,這樣是不是很巧妙呢?

在介面申明的標頭檔案中最好不要出現如cstring等只有在mfc中才會出現的變數型別,盡量用通用的變數型別,例如cstring用lpctstr代替等,這樣vb的程式也能呼叫你的介面,如果用cstring的話,vb的程式就識別不了了。

此方案提供給呼叫者的不是乙個介面申明標頭檔案,而是乙個類(一般是兩個檔案,乙個.cpp和乙個.h),該類中封裝了dll中的所有介面的實現,通過這種方案,呼叫者就可以像使用乙個普通的類一樣來使用你的dll的介面了,是不是覺得很方便呢!呵呵,下面詳細介紹這種方案的實現步驟。

名字暫且稱為cdll吧,先介紹標頭檔案,標頭檔案一般需要這樣寫:

class cdll

幾個需要注意的地方:

ø         cdll中必須要提供dll中所有介面的呼叫,而且必須是一對一的方式,不要去改動dll的呼叫邏輯,cdll只是提供乙個簡單介面呼叫的過渡而已。

ø         cdll中成員函式的名稱應盡量和dll介面函式的名稱類似,這樣看起來比較統一,可讀性好。

寫完標頭檔案後,就讓我們實現.cpp檔案吧:

ø         建構函式

cdll()::cdll()

ø         析構函式

cdll()::~cdll()

// 其它記憶體的清理工作

}ø         bool init ()  初始化函式的寫法

m_handle = ::loadlibrary(_t(「cdll.dll」));    // 載入dll

if ( !m_handle )  

m_pfn inte***cea =( lp inte***cea)::getproaddress(m_handle, _t(「介面名」);

// 其它介面按同樣的方式進行初始化

return true;

}ø         bool uninit ()  反初始化函式的寫法

return true;

}ø         bool cdll::inte***cea()   // 終於到介面的實現了,呵呵

}return false;

}ø         其它介面的實現,參照cdll::inte***cea()的實現方法就可以了

到這裡,我們的介面類就全部寫完了,呼叫者要使用dll的介面就非常的方便了,例如要使用dll的_xx_loaddll bool inte***cea(lpctstr/*[in]*/);介面,現在只用這樣就可以了:

cdll dll;

dll. inte***cea();

是不是覺得很方便呢??呵呵…而且這種方式實現的類是乙個可以重用的類,充分體現了物件導向中**重用的思想。

和方案一一樣,需要提供乙個標頭檔案,不管dll有多少個介面,對外開放的介面卻只有乙個,但是呼叫者可以訪問dll的所有介面,是不是覺得很玄乎?呵呵,不賣關子了,直接進入主題。標頭檔案一般需要像這樣寫:

typedef  bool (*lpinte***cea)(lpctstr/*[in]*/); // 不用extern 「c」…了

// 其它介面的申明

注意這些介面必須在dll**中實現。

typedef struct inte***ce

}inte***ce,*lpinte***ce;

_xx_loaddll  bool lpgetallinte***ce(inte***ce* pinte***ce);

typedef  bool (*lpgetallinte***ce)( inte***ce* pinte***ce /*[in/out]*/);

介面lpgetallinte***ce必須完成pinte***ce各成員的初始化工作,比較推薦的方式是:在dll內部將lpinte***cea (lpctstr/*[in]*/)定義為全域性變數,而lpgetallinte***ce介面就可以這樣實現

lpgetallinte***ce( inte***ce* pinte***ce /*[in/out]*/)

至此,整個標頭檔案就寫完了,呼叫者就可以這樣呼叫dll了,

inte***ce inte***ce;

inte***ce.init();

lpgetallinte***ce lpgetallite***ce;

lpgetallinte***ce(&inte***ce);

if ( inte***ce. m_pfninte***cea)

此方案是受到com程式設計思想的啟發,這樣一來,對外界來說,dll永遠只有乙個不變的介面,在某些場合,這是非常重要的,而且這種方法可以在不改變介面的情況下增加新的介面,新的功能,雖然這句話聽起來有點拗口,但卻是一種很好擴充套件dll功能的實現方案。

第一種方案是一種比較傳統的方式,而第二種方式充分體現了物件導向的程式設計思想,實現了**的重用,而第三種方式個人持「中立」觀點,一般不會用到它,我之所以把它也寫出來,是希望我們的開發思路不要一直走直線,偶爾轉轉彎,也許你真的能發現一條捷徑!

VC環境下DLL介面申明的三種方式

本文將介紹三種提供dll介面的方式 對於如何編寫dll內部的 不做介紹 由於筆者工作時間不長,難免有疏漏的之處,還請各位大俠不吝賜教,謝謝!在dll中寫好介面的實現 後,然後提供乙個申明介面的標頭檔案供呼叫者使用,我想一般都會這樣寫 ifdef dllname xx define xx loaddl...

C 碼農 VC環境下DLL介面申明的三種方式

本文將介紹三種提供dll介面的方式 對於如何編寫dll內部的 不做介紹 由於筆者工作時間不長,難免有疏漏的之處,還請各位大俠不吝賜教,謝謝!在dll中寫好介面的實現 後,然後提供乙個申明介面的標頭檔案供呼叫者使用,我想一般都會這樣寫 ifdef dllname xx define xx loaddl...

VC三種型別的DLL區別

1 regular statically linked to mfc dll 標準靜態鏈結mfc dll 編譯時鏈結 占用空間大,不依賴於其它的dll 2 regular using the shared mfc dll 標準動態鏈結mfc dll 編譯時不鏈結 占用空間小,依賴於其它的dll 以上...