使用DLL中的資源

來源:互聯網
上載者:User

我很早的時候寫過一篇MFC中CDialog與其對話方塊資源的綁定,但這幾天在MFC DLL上做了一些工作後發現當時的理解實在膚淺。說不定過了幾年再回頭看看目前這篇文章,又覺得本文也是鬼話連篇了吧,哈哈。

使用DLL中的資源面臨的一個主要問題是,DLL和EXE中都有資源集,但是程式在運行態到底會去哪個資源集中找常常令我們疑惑。
考慮如下的經典情況:

在建立MFC DLL工程時選中Regular DLL using shared MFC DLL選項,建立一個與MFC自身DLL共用的DLL。在新DLL中建立一個ID名為IDD_DLLDIALOG的對話方塊資源。在這個DLL中匯出一個ShowDialog()函數,內容如下:

查看原始碼

 

列印協助

1 extern "C" void Show Dialog()
2 {
3     CDialog dlg(IDD_DLLDIALOG);
4     dlg.DoModal();
5 }

建立一個MFC的EXE工程,匯入剛剛建立的DLL工程的lib和dll,將OK按鈕的響應函數設定為:  ShowDialog();  編譯連結通過後,我們運行起程式來會發現點擊OK按鈕後什麼反應都沒有!怎麼會這樣?我們不是明明在DLL裡設定好了IDD_DLLDIALOG嗎?請大家注意“在建立MFC DLL工程時選中Regular DLL using shared MFC DLL”這句話,如果我們當時選的是“Regular DLL with MFC statically linked”又會是什麼情況呢?又能正常顯示了!

使用靜態串連的方式訪問MFC庫DLL,會把MFC庫DLL與工程本身一起打包,而共用的方式則會在運行時去系統路徑中動態載入MFC庫DLL。我們可以這麼理解以上的現象:如果建立的DLL使用共用的方式訪問庫DLL,當EXE程式運行時,實際上有兩套上下文系統在運作,而靜態串連則只有一套上下文系統了,因此在靜態串連時會需要進行模組狀態的切換。

當我們建立的是共用方式訪問 庫DLL的DLL時,要解決上述問題比較通用的做法是在ShowDialog函數裡面加上一句AFX_MANAGE_STATE(AfxGetStaticModuleState());

AfxGetStaticModuleState()的原型為:

AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState( );

即當前模組的ModuleState指標。

AFX_MANAGE_STATE宏則會以傳入的指標為參數去在棧上建立一個類,此類會做哪些事相信聰明的你也能猜到了.沒錯,它會在建構函式中存下當前的ThreadState所指向的ModuleState指標,再將傳入的指標指定為當前ThreadState所指向的指標。等到這個類的執行個體被析構是,又將其改回去。

令外一種方法是使用AfxGetResourceHander()配合AfxSetResourceHander(HINSTANCE)了(這也正是我在MFC中CDialog與其對話方塊資源的綁定中介紹的方法)。

如果我們不想在EXE中通過間接的調用DLL匯出的ShowDialog(),而是直接想在EXE的OnBnClickedOk()中產生一個使用DLL中對話方塊資源的對話方塊呢?這時AFX_MANAGE_STATE(AfxGetStaticModuleState())就派不上用場了(因這它是用在DLL工程中的)。最好的辦法是用AfxSetResourceHander(HINSTANCE)配合GetModuleHandle(LPCTSTR)。

GetModuleHandle(LPCTSTR str)將會根據傳入的字串得到相應的模組控制代碼。注意,EXE和DLL都可以被看作是模組。當傳入為空白(NULL)時,將得到當前進程(EXE)的HINSTANCE控制代碼。使用GetModuleHandle要保證相應的dll已經被載入,也許你會說這個條件不是廢話麼,但是這確實是很容易犯錯的地方。

如果是用靜態載入DLL的方式(即直接把產生的那個.lib檔案匯入),而之前又從未調用過這個dll中的任何函數或變數的話,GetModuleHandle只會得到一個空值。因為系統會直到有某個語句調用過dll裡面的東西時才會將dll真正載入。

例如:

查看原始碼

 

列印協助

1 void CUseDllDlg::OnBnClickedOk()
2 {
3     HINSTANCE temp = AfxGetResourceHandle();
4     AfxSetResourceHandle(GetModuleHandle(_T("RegDll")));
5     CDialog dlg(4000);
6     dlg.DoModal();
7     AfxSetResourceHandle(temp);
8 }

上面的這份代碼運行時會報錯,因為AfxSetResourceHandle在檢查入參時發現了個空值。而下面的代碼則不會有問題:

查看原始碼

 

列印協助

1 void CUseDllDlg::OnBnClickedOk()
2 {
3     ASSERT(TestOnly() == 1);
4     HINSTANCE temp = AfxGetResourceHandle();
5     AfxSetResourceHandle(GetModuleHandle(_T("RegDll")));
6     CDialog dlg(4000);
7     dlg.DoModal();
8     AfxSetResourceHandle(temp);
9 }

其中TestOnly也是從RegDll中匯出的函數,它什麼都不做,只是返回一個1。我們使用它只是為了把RegDll載入進來。當然了,如果我們直接使用動態載入的方法,像下面這樣直接LoadLibrary那更是沒有問題了。

查看原始碼

 

列印協助

1 void CUseDllDlg::OnBnClickedOk()
2 {
3     HMODULE hm= LoadLibrary(_T("..//Debug//RegDll.dll"));
4     HINSTANCE temp = AfxGetResourceHandle();
5     AfxSetResourceHandle(GetModuleHandle(_T("RegDll")));
6     CDialog dlg(4000);
7     dlg.DoModal();
8     AfxSetResourceHandle(temp);
9 }

不過眼尖的讀者可能會立即發現其實在上面這種情況下使用GetModuleHandle不是最好的選擇。因為直接來個AfxSetResourceHandle(hm)就可解決問題了。

 

from:http://www.thankcreate.com/c/275

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.