本文將介紹三種提供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 以上...