對(duì)于普通的DLL項(xiàng)目中使用的.def文件通常會(huì)引起LNK4017鏈接告警,如下所示:
.ComFunc.def(4) : warning LNK4017: DESCRIPTION statement not supported for the target platform; ignored
Creating library ...Debug/ComFunc.lib and object ...Debug/ComFunc.exp
一個(gè)典型的.def文件通常有以下內(nèi)容:
LIBRARY "XorCryptor"
DESCRIPTION 'XorCryptor Windows Dynamic Link Library'
EXPORTS
; Explicit exports can go here
..................
消除這個(gè)連接告警的方法就是從.def文件中刪除DESCRIPTION描述信息,不過(guò)這個(gè)告警也不是什么大問(wèn)題,不刪也可以。另一個(gè)可能產(chǎn)生的連接告警是LNK4222,通常出現(xiàn)在ocx控件和com組件的項(xiàng)目中,一個(gè)典型輸出是:
Linking...
.PlusInModule.def : warning LNK4222: exported symbol 'DllCanUnloadNow' should not be assigned an ordinal
.PlusInModule.def : warning LNK4222: exported symbol 'DllGetClassObject' should not be assigned an ordinal
.PlusInModule.def : warning LNK4222: exported symbol 'DllRegisterServer' should not be assigned an ordinal
.PlusInModule.def : warning LNK4222: exported symbol 'DllUnregisterServer' should not be assigned an ordinal
出現(xiàn)這個(gè)告警的原因是舊的項(xiàng)目的.def文件通常這樣定義ocx和com必需的四個(gè)導(dǎo)出函數(shù):
EXPORTS
DllCanUnloadNow @1 PRIVATE
DllGetClassObject @2 PRIVATE
DllRegisterServer @3 PRIVATE
DllUnregisterServer @4 PRIVATE
其中為這四個(gè)重要的導(dǎo)出函數(shù)指定了四個(gè)順序號(hào)。Windows平臺(tái)上通常用兩種方式定位DLL文件中的導(dǎo)出函數(shù),一種是根據(jù)導(dǎo)出函數(shù)名稱,一種是根據(jù)順序號(hào),上學(xué)時(shí)曾經(jīng)寫(xiě)過(guò)一個(gè)顯示圖片的程序,能處理大多數(shù)當(dāng)時(shí)流行的圖像格式文件,唯獨(dú)jpeg格式的搞不定,有一次看到一個(gè)圖像處理軟件中包含了一個(gè)LoadJpeg.dll,很顯然這個(gè)DLL是處理jpeg格式的圖像文件的嘛,于是趕快用depends look了一下,頓時(shí)高喊:鬼啊~~~。原來(lái)這個(gè)depends竟然查不到導(dǎo)出函數(shù)的名字,后來(lái)才知道還有NONAME參數(shù)強(qiáng)制用順序號(hào)定位導(dǎo)出函數(shù),于是就常常弄個(gè)沒(méi)有導(dǎo)出函數(shù)名字的DLL到處show。。。。嗯,又扯遠(yuǎn)了。話說(shuō)為什么舊的系統(tǒng)要以此指定這四個(gè)導(dǎo)出函數(shù)的順序號(hào)我就沒(méi)有研究了,反正現(xiàn)在不需要指定了,只要將@1,@2之類的刪除就行了,不過(guò)不刪好像也沒(méi)什么問(wèn)題,它們會(huì)被自動(dòng)忽略。
六、使用MFC的消息映射宏引起的編譯錯(cuò)誤
錯(cuò)誤現(xiàn)象之一:
f:project.....plusmaindlg.cpp(220) : error C2440: 'static_cast' : cannot convert from 'void (__thiscall CPlusMainDlg::* )(int,BOOL)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
None of the functions with this name in scope match the target type
錯(cuò)誤現(xiàn)象之二:
f:project.....crpfileopavdlg.cpp(87) : error C2440: 'static_cast' : cannot convert from 'LRESULT (__thiscall CCrpFileOpavDlg::* )(LPCTSTR,int)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
None of the functions with this name in scope match the target type
以上兩個(gè)編譯錯(cuò)誤產(chǎn)生是因?yàn)樾屡f版本的MFC 中對(duì)ON_MESSAGE消息映射宏定義不同引起的,先看看老版本的MFC的ON_MESSAGE消息宏定義:
#define ON_MESSAGE(message, memberFxn)
{ message, 0, 0, 0, AfxSig_lwl,
(AFX_PMSG)(AFX_PMSGW)(LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM))&memberFxn },
再看看新版本的ON_MESSAGE定義:
#define ON_MESSAGE(message, memberFxn)
{ message, 0, 0, 0, AfxSig_lwl,
(AFX_PMSG)(AFX_PMSGW)
(static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) >
(memberFxn)) },
注意,函數(shù)類型沒(méi)有變化,都是:
LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM);
類型的函數(shù)指針(CWnd以及派生類的類成員函數(shù)指針),區(qū)別之處是新的ON_MESSAGE宏使用C++的 static_cast 操作符代替了C類型的強(qiáng)制轉(zhuǎn)換。產(chǎn)生這兩個(gè)錯(cuò)誤其實(shí)是因?yàn)橛脩魶](méi)有按照ON_MESSAGE宏的約定聲明和定義消息響應(yīng)函數(shù)造成的,比如,對(duì)于某些不需要處理返回值的消息響應(yīng)函數(shù),用戶通常這樣聲明和定義消息響應(yīng)函數(shù):
在頭文件中聲明:
afx_msg void OnFileProcess(WPARAM wParam,LPARAM lParam);
在源文件中實(shí)現(xiàn):
void CCrpFileOpavDlg::OnFileProcess(WPARAM wParam, LPARAM lParam)
{
.......
}
或者更過(guò)分一些,直接指定為實(shí)際參數(shù)類型:
在頭文件中聲明:
afx_msg void OnFileProcess(LPCTSTR lpszMessage, int nPercent);
在源文件中實(shí)現(xiàn):
void CCrpFileOpavDlg::OnFileProcess(LPCTSTR lpszMessage, int nPercent)
{
.......
}
舊版本的ON_MESSAGE使用了C類型的強(qiáng)制轉(zhuǎn)換,宏解開(kāi)后的代碼后不會(huì)產(chǎn)生錯(cuò)誤信息,但是改成對(duì)類型檢查很嚴(yán)格的static_cast 操作符時(shí)就出問(wèn)題了,因?yàn)橥ú贿^(guò)static_cast 操作符的檢查。解決方法就是修改代碼,同時(shí)吸取教訓(xùn),普遍使用的方法并不一定就能約定俗成,一切還是要按照規(guī)矩來(lái)。
聯(lián)系客服