從VC6到VC9移植代碼問題總結(jié) 收藏
當年在學校學習C編程的時候用的是TC2.0,,后來學C++用TC3.0,,有一天突然發(fā)現(xiàn)Borland C++ 3.1的IDE比較好用,,于是改用BC31,,然后是BC4,,但是到了BC5(還有BC5.02)的時候就玩不下去了,,因為我那臺只有16M內(nèi)存的P100實在是跑不動這個龐然大物,在OWL和MFC之間“痛苦地”抉擇了一部電影的時間后,,我決定放棄添加內(nèi)存的計劃,,改用Visual C++試試,。因為當時內(nèi)存太貴了,,不過電影很好看,,我還記得名字是《西域雄獅》,講的是黃飛鴻到北美開寶之林分號的故事,,還收了一個洋徒,。。,。你看這思維跳躍的,,打住,說正事兒吧,??赐觌娪昂笱b了一個Visual C++ 4.2,這Microsoft的東西就是爭氣,,在我的破機器上跑得馬溜的快,于是就用買內(nèi)存的預算買了一本《Visual C++ 4.0從入門到精通》,,那個時候的出版社就是效率低,,這本書已經(jīng)是所有關于VC的書中最新的了,好像還看到一本《Visual C++ 1.5-2.x 使用指南》,,什么年代的事情了,,還擺在書架上。哪像現(xiàn)在的出版社,,簡直就是“與時俱進”的典范,,Microsoft那邊 《Windows 7》 剛發(fā)布了個預覽版,這邊《下一代xxx揭密》就已經(jīng)上架了,,唉,,又扯遠了,,打住。沒多久VC5就出來了,,好在這兩個版本的用戶界面變化不大(MFC的版本穩(wěn)定在4.2),,我就在《Visual C++ 4.0從入門到精通》這本書的指導下“精通”了VC5。1998年的時候Visual C++ 6.0推出了,,但是我一直堅持用VC5,,1999年我畢業(yè)設計還是選擇用VC5,不為別的,,就是因為當時盜版的VC6都沒有幫助文件,,就是缺少MSDN,沒有這個還怎么寫代碼,?畢業(yè)設計完成之后我從朋友那里弄到了傳說中的兩張MSDN光盤,,于是開始用VC6,從此以后,,VC6就一直存在于所有我用過的電腦中,,后來VC7(7.1),VC8出來以后,,VC6的地位也一直沒有動搖過,,用C++開發(fā)軟件我首選VC6,我還為VC6開發(fā)了一個文件標簽欄插件Tabbar,,可以通過標簽欄在打開的代碼文件之間快速切換,,除此之外還具有很多其它功能,比如自動打包壓縮項目代碼,。,。。唉,,又跑題了,,打住。 做人要與時俱進,,這不,,今年VC9也隨著Visual Studio 2008發(fā)布了,再不趕上就真的老套了,。說是這么說,,不過心里還是有些余悸的,2006年的時候我曾經(jīng)試圖將我的一個工具軟件的代碼升級到VC8,,但是我低估了新的編譯器的兼容性(當年從VC5到VC6可是沒有那么多麻煩),,上來就是一大堆編譯錯誤,警告就更是牛毛,,當時因為急著為工具軟件開發(fā)一個新功能,,沒有時間解決這些問題,,只好放下了,這一放就是兩年,。我這個人喜歡自己做工具軟件,,目的是為了方便自己,以前用VC6,,覺得在代碼源文件之間切換很麻煩,,但是WndTab太占用資源,于是就借鑒WndTab的部分代碼自己做了個標簽欄插件Tabbar,,還把從CodeProject上看到的好的創(chuàng)意都添加進去,,后來用Source Insight,覺得它沒有文件標簽欄太土,,就給它做了個標簽欄外掛(TabSiPlus),,就這樣幾年下來竟然有幾百兆的工具代碼,這個移植的工作量可是非同小可,,想著都怕怕呀,!不過也沒辦法,這兩年主要用GCC做嵌入式開發(fā)了,,沒有時間維護這些工具,,自己在使用過程中累計下來的BUG和新需求也有一大堆,需要進行升級了,,適逢這次機會將其移植到VC9到也是個不錯的選擇,。其實程序員自己給自己寫工具很有好處,比如我喜歡邊寫代碼邊聽音樂,,于是我就把自己寫的MP3播放器集成到VC開發(fā)環(huán)境中,,這樣就可以象操作VC的其它功能一樣選擇音樂文件,還比如,。,。。又扯遠了,,回到正題,,講講移植過程中遇到的問題。
首先可以直接用Visual Studio 2008的打開VC6的工作區(qū)文件和項目文件(dsw和dsp),,并將其升級為VS2008的解決方案格式和項目格式(sln和vcproj),,VC9的編譯器相對于VC6有了很大的變化,,一些編譯參數(shù)和鏈接參數(shù)被廢棄(比如/map:line),,有一些改變了名稱,還有新增的選項,不過不用擔心,,升級過程會自動對其進行轉(zhuǎn)換,,最終都會得到一個正確的解決方案和VC項目文件,,這個過程不會遇到太多的麻煩,問題都出在隨后的編譯過程中,,下面就將我在移植的過程中遇到的問題和我的解決方法總結(jié)一下,,希望對還在用VC6維護代碼的朋友有所幫助。
一,、_WIN32_WINNT 與 _WIN32_IE 設置沖突
_WIN32_WINNT 與 _WIN32_IE設置不兼容會導致如下C1189致命錯誤:
StdAfx.cpp
c:\program files\microsoft sdks\windows\v6.0a\include\sdkddkver.h(217) : fatal error C1189: #error : _WIN32_WINNT settings conflicts with _WIN32_IE setting StdAfx.cpp通常是項目中第一個編譯的文件,,這個錯誤將導致編譯無法繼續(xù)進行。產(chǎn)生這個錯誤的原因是原因是_WIN32_WINNT的版本定義太老,,老的VC代碼對_WIN32_WINNT的典型設置是:
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400 #endif 0x0400相對于VS2008所帶的Plarform SDK(在文件sdkddkver.h中)中_WIN32_IE的定義來說太老了,,導致不兼容,可以將其改成0x0501或更高的版本避免這個問題,,如下所示:
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501 #endif 也可以將這三行_WIN32_WINNT定義刪除,,這樣就會使用Plarform SDK中的_WIN32_WINNT定義,自然就不存在不兼容問題了,。不過出于對老版本VC的兼容考慮(畢竟以后可能還要使用VC6編譯代碼),,最好這樣修改:
#if _MSC_VER <= 1200 // MFC 6.0 or earlier
#ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0400 #endif #endif 二、afximpl.h文件中的語法錯誤
MFC出現(xiàn)的時候STL還沒有成為C++的標準,,所以MFC使用一套自己的模版庫,,比如CArray、CList,、CMap等等,,這些類型聲明都在afximpl.h文件中。原來在VC6編譯器適用的模版語法可能不適用VC9,,特別是當以下四個環(huán)境變量設置不兼容時,,就會出現(xiàn)這個編譯錯誤,大致情況如下:
e:\software\microsoft visual studio 9.0\vc\atlmfc\src\mfc\afximpl.h(625) : error C2059: syntax error : '<L_TYPE_raw>'
e:\software\microsoft visual studio 9.0\vc\atlmfc\src\mfc\afximpl.h(625) : error C2238: unexpected token(s) preceding ';' e:\software\microsoft visual studio 9.0\vc\atlmfc\src\mfc\afximpl.h(629) : error C2059: syntax error : '<L_TYPE_raw>' e:\software\microsoft visual studio 9.0\vc\atlmfc\src\mfc\afximpl.h(629) : error C2238: unexpected token(s) preceding ';' 合理調(diào)整stdafx.h中WINVER,、_WIN32_WINNT,、_WIN32_WINDOWS和_WIN32_IE的設置可以避免這個問題,將三個與Windows版本有關的環(huán)境變量設置為0x0501或更高版本,,將IE版本的環(huán)境變量設置為0x0500以后的版本就可以解決這個問題,。當然,考慮到與舊的VC6代碼兼容,,可以采用上一個問題中提到的最后一個解決辦法,,用_MSC_VER進行隔離。
三,、 舊的CRT庫和新的安全CRT庫引起的C4996告警 解決了環(huán)境變量設置不匹配導致的問題后,,編譯過程就真正開始了,不過首先映入眼簾的應該是成堆的C4996編譯告警,對每個使用了含字符串參數(shù)的CRT庫函數(shù)都會有C4996編譯告警,,一個典型的輸出如下所示:
f:\project\.....\commonfunc.cpp(280) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
e:\software\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' MSDN online 是這樣解釋的:為了顯著增加CRT庫的安全性,,許多CRT函數(shù)都有了一個更安全的新版本,新版本和舊版本的區(qū)別就是新版本函數(shù)名多了一個_s后綴,。只要一個CRT函數(shù)有新的安全版本,,編譯器就會產(chǎn)生一個C4996告警,不過,,出現(xiàn)這個告警的目的并不是說舊版本的CRT函數(shù)將淡出CRT庫,,告警出現(xiàn)只是為了提醒程序員這個函數(shù)有更安全的版本存在。一種安全的或者是被鼓勵的做法是用安全版本的函數(shù)替換現(xiàn)有的CRT函數(shù),,不過對于一個有相當代碼量的項目,,替換工作量也是巨大的,這可不是用名稱查找,、替換就能簡單解決的問題,,因為許多安全版本的CRT函數(shù)參數(shù)個數(shù)也發(fā)生了變化。也可以用預處理指令消除這個告警:
#pragma warning( disable : 4996 ) 或者定義 _CRT_SECURE_NO_WARNINGS 壓制這個告警(在stdafx.h中define或在項目屬性中設置預處理符號,PreProcessor Definitions),。 除了C語言的CRT函數(shù)外,,POSIX 兼容函數(shù)也存在這個告警,解決方法是用POSIX標準名稱替換(比如access換成_access)或者是定義 _CRT_NONSTDC_NO_WARNINGS 壓制這個告警(方法同上),。
四,、“CWinApp::Enable3dControls”引起的C4996告警 這個是編譯使用了老的向?qū)傻腗FC代碼時遇到的問題,一個典型的告警信息輸出如下所示:
CrpFileCrack.cpp
f:\project\.....\crpfilecrack.cpp(52) : warning C4996: 'CWinApp::Enable3dControls': CWinApp::Enable3dControls is no longer needed. You should remove this call. e:\software\microsoft visual studio 9.0\vc\atlmfc\include\afxwin.h(4818) : see declaration of 'CWinApp::Enable3dControls' 通常向?qū)傻拇a是:
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif 這兩個函數(shù)的調(diào)用是舊的MFC版本對新版本的操作系統(tǒng)特性的支持,,在新的(那個時候是新的)Windows 95平臺上要這樣調(diào)用一下才能使用新的Windows 3D樣式的控件,,否則就是老的Win 3.2樣子的控件。想當初喜歡OWL就是因為感覺它的控件比較“酷”,,比如那個帶底紋的對話框,,菱形的checkbox,還有帶圖標的“OK”按鈕,,看到MFC作出來的灰灰的界面就覺得土,,不過后來就知道MFC做界面也是很漂亮的,比如我做的,。,。。,。,,再打住。對于新的MFC版本來說已經(jīng)不需要再調(diào)用這兩個函數(shù)了,,參考前面的方法,,用_MSC_VER對其隔離就行了:
#if _MSC_VER <= 1200 // MFC 6.0 or earlier
#ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif #endif 五,、.def文件引起的連接告警 對于普通的DLL項目中使用的.def文件通常會引起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 一個典型的.def文件通常有以下內(nèi)容:
LIBRARY "XorCryptor"
DESCRIPTION 'XorCryptor Windows Dynamic Link Library' EXPORTS
; Explicit exports can go here .................. 消除這個連接告警的方法就是從.def文件中刪除DESCRIPTION描述信息,,不過這個告警也不是什么大問題,不刪也可以,。另一個可能產(chǎn)生的連接告警是LNK4222,,通常出現(xiàn)在ocx控件和com組件的項目中,一個典型輸出是: 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)這個告警的原因是舊的項目的.def文件通常這樣定義ocx和com必需的四個導出函數(shù):
EXPORTS DllCanUnloadNow @1 PRIVATE DllGetClassObject @2 PRIVATE DllRegisterServer @3 PRIVATE DllUnregisterServer @4 PRIVATE 其中為這四個重要的導出函數(shù)指定了四個順序號,。Windows平臺上通常用兩種方式定位DLL文件中的導出函數(shù),,一種是根據(jù)導出函數(shù)名稱,一種是根據(jù)順序號,,上學時曾經(jīng)寫過一個顯示圖片的程序,,能處理大多數(shù)當時流行的圖像格式文件,唯獨jpeg格式的搞不定,,有一次看到一個圖像處理軟件中包含了一個LoadJpeg.dll,,很顯然這個DLL是處理jpeg格式的圖像文件的嘛,于是趕快用depends look了一下,,頓時高喊:鬼啊~~~,。原來這個depends竟然查不到導出函數(shù)的名字,后來才知道還有NONAME參數(shù)強制用順序號定位導出函數(shù),,于是就常常弄個沒有導出函數(shù)名字的DLL到處show,。。,。,。嗯,又扯遠了,。話說為什么舊的系統(tǒng)要以此指定這四個導出函數(shù)的順序號我就沒有研究了,,反正現(xiàn)在不需要指定了,只要將@1,,@2之類的刪除就行了,,不過不刪好像也沒什么問題,它們會被自動忽略,。
六,、使用MFC的消息映射宏引起的編譯錯誤 錯誤現(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 錯誤現(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 以上兩個編譯錯誤產(chǎn)生是因為新舊版本的MFC 中對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ù)類型沒有變化,,都是:
LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM); 類型的函數(shù)指針(CWnd以及派生類的類成員函數(shù)指針),區(qū)別之處是新的ON_MESSAGE宏使用C++的 static_cast 操作符代替了C類型的強制轉(zhuǎn)換,。產(chǎn)生這兩個錯誤其實是因為用戶沒有按照ON_MESSAGE宏的約定聲明和定義消息響應函數(shù)造成的,,比如,,對于某些不需要處理返回值的消息響應函數(shù),用戶通常這樣聲明和定義消息響應函數(shù): 在頭文件中聲明:
afx_msg void OnFileProcess(WPARAM wParam,LPARAM lParam); 在源文件中實現(xiàn):
void CCrpFileOpavDlg::OnFileProcess(WPARAM wParam, LPARAM lParam) { ....... } 或者更過分一些,,直接指定為實際參數(shù)類型:
在頭文件中聲明:
afx_msg void OnFileProcess(LPCTSTR lpszMessage, int nPercent); 在源文件中實現(xiàn):
void CCrpFileOpavDlg::OnFileProcess(LPCTSTR lpszMessage, int nPercent) { ....... } 舊版本的ON_MESSAGE使用了C類型的強制轉(zhuǎn)換,,宏解開后的代碼后不會產(chǎn)生錯誤信息,但是改成對類型檢查很嚴格的static_cast 操作符時就出問題了,,因為通不過static_cast 操作符的檢查,。解決方法就是修改代碼,同時吸取教訓,,普遍使用的方法并不一定就能約定俗成,,一切還是要按照規(guī)矩來。
錯誤現(xiàn)象之三: f:\project\.....\WzButton.cpp(74) : error C2440: 'static_cast' : cannot convert from 'UINT (__thiscall CWzButton::* )(CPoint)' to 'LRESULT (__thiscall CWnd::* )(CPoint)'
Cast from base to derived requires dynamic_cast or static_cast 出現(xiàn)這個錯誤的原因可是“人力不可抗拒”之原因造成的,,因為舊版本的 ON_WM_NCHITTEST 宏使用了
UINT (__thiscall CWzButton::* )(CPoint); 類型的類成員函數(shù)指針,,其定義如下: #define ON_WM_NCHITTEST() \
{ WM_NCHITTEST, 0, 0, 0, AfxSig_wp, \ (AFX_PMSG)(AFX_PMSGW)(UINT (AFX_MSG_CALL CWnd::*)(CPoint))&OnNcHitTest }, 但是新版本變成了:
#define ON_WM_NCHITTEST() \
{ WM_NCHITTEST, 0, 0, 0, AfxSig_l_p, \ (AFX_PMSG)(AFX_PMSGW) \ (static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(CPoint) > (&ThisClass :: OnNcHitTest)) }, 注意返回值類型由UINT改成了LRESULT,再加上static_cast的嚴格檢查,,所以就出錯了,。修改的方法就是將你的OnNcHitTest函數(shù)由:
afx_msg UINT OnNcHitTest(CPoint point);
改成:
afx_msg LRESULT OnNcHitTest(CPoint point);
不必太在意,這個不是你的錯,,不過,,如果你要維護一個老的界面庫(通常很多控件的subclass都會用到ON_WM_NCHITTEST),改起來還是很痛苦地,,不扯了,,繼續(xù)下一個。
七,、statreg.cpp 和 atlimpl.cpp 的廢棄(obsolete)問題 在編譯老的ATL向?qū)傻拇a時,,會遇到下面的編譯輸出:
StdAfx.cpp
statreg.cpp is obsolete. Please remove it from your project. atlimpl.cpp is obsolete. Please remove it from your project. 因為老的ATL向?qū)傻拇a通常在stdafx.cpp文件中添加以下代碼:
#ifdef _ATL_STATIC_REGISTRY
#include <statreg.h> #include <statreg.cpp> #endif #include <atlimpl.cpp>
根據(jù)提示刪除#include <statreg.cpp>和#include <atlimpl.cpp>兩行代碼就行了,不過更好的辦法是這樣改:
#ifdef _ATL_STATIC_REGISTRY
#include <statreg.h> #if _MSC_VER <= 1200 // MFC 6.0 or earlier #include <statreg.cpp> #endif #endif #if _MSC_VER <= 1200 // MFC 6.0 or earlier
#include <atlimpl.cpp> #endif 八,、新的C++編譯器不再支持默認類型的變量定義 錯誤現(xiàn)象是: f:\project\.....\WzCheckBox.cpp(464) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int 產(chǎn)生這個錯誤的原因是程序中出現(xiàn)了這樣的代碼:
const some_const_var = 10;
或
static some_static_bool = FALSE;
新的C++編譯器嚴格按照C++標準,,不再支持默認類型的變量定義方式,必須嚴格指定變量類型,,如下使用:
const int some_const_var = 10;
或
static BOOL some_static_bool = FALSE;
九,、for 語句的變量作用域問題 考察下面的代碼:
for(int i = 0; i < 120; i++)
{ if(something_happen) { break; } ............. } if(i < 120)
{ //something happen } 在VC6的編譯器中,這樣的代碼是沒有問題的,,因為VC6的編譯器為了兼容舊的Microsoft C/C++編譯器,,沒有嚴格按照C++標準執(zhí)行,但是從VC7開始,,VC的編譯器開始遵守C++標準,,所以就會出現(xiàn)“變量i沒有定義的錯誤”。解決的方法也很簡單,,按照Jim Hyslop 和 Herb Sutter的經(jīng)典對話系列的第四篇中的方法,,改成如下就可以了:
int i;
for(i = 0; i < 120; i++) 十,、字符串函數(shù)的返回值問題
strchr(_tcschr)、strpbrk(_tcspbrk ??),、strrchr(_tcsrchr)和strstr(_tcsstr)這四個函數(shù)在VC6的CRT庫中定義的返回值都是char *(TCHAR *),,所以以前的代碼通常是這樣使用的:
TCHAR *cp = _tcschr( pszPath, _T('\\') );
//使用*cp,可以通過cp指針修改pszPath的內(nèi)容 這其實是一個“漏洞”,,因為如果pszPath是const char(TCHAR) *字符串,,那么就表示它不希望修改字符串的內(nèi)容,但是調(diào)用strchr(_tcschr)函數(shù)后就可以通過cp指針修改其內(nèi)容了,,這豈不荒謬?所有在新版本的CRT庫中,,這幾個函數(shù)的返回值都改成const char *,,這就會導致上面的代碼產(chǎn)生編譯錯誤。建議的修改方式是改成如下方式:
const TCHAR *cp = _tcschr( pszPath, _T('\\') );
//不能再通過cp指針修改pszPath的內(nèi)容 但是這樣修改可能對代碼的影響比較大,,比如下面的代碼:
TCHAR buf[256]; //局部緩沖區(qū) ...... TCHAR *cp = _tcschr( buf, _T('\\') ); //作為局部緩沖區(qū)(非const),,希望通過cp修改buf的內(nèi)容 這種情況怎么辦呢?對了,,C++還有個const_cast操作符,,這時就可以排上用場了:
TCHAR *cp = const_char<TCHAR *>(_tcschr( buf, _T('\\') ));
不過上面的方法要慎用,除非確定buf是非const的,,否則最好老老實實地修改代碼,。
十一、類成員函數(shù)指針做為函數(shù)參數(shù)的“C3867”錯誤 考察下面的代碼,,CWzWindowsHook類的構(gòu)造函數(shù)使用一個該類的成員函數(shù)指針,,這樣構(gòu)造對象時可以選擇消息過濾的handler,可以是MouseMsgFilter,,也可以是KeyboardMsgFilter:
typedef BOOL (CWzWindowsHook::*FILTERPROC)(WPARAM wParam, LPARAM lParam);
// A hook used in customization sheet to filter keyboard/mouse events
class CWzWindowsHook { private: FILTERPROC m_pFilter; BOOL MouseMsgFilter(WPARAM wParam, LPARAM lParam); BOOL KeyboardMsgFilter(WPARAM wParam, LPARAM lParam); public: CWzWindowsHook(FILTERPROC pFilter) : m_pFilter(pFilter) 舊的遺留代碼存在這樣的用法: CWzWindowsHook mouseHooker(CWzWindowsHook::MouseMsgFilter);
在VC6的編譯器下編譯可能沒有問題,,但是在VC9的編譯器下編譯會有如下報錯:
f:\project\.....\WzWindowsHook.cpp(272) : error C3867: 'CWzWindowsHook::MouseMsgFilter': function call missing argument list; use '&CWzWindowsHook::MouseMsgFilter' to create a pointer to member
雖然C++從C繼承來了函數(shù)名即是函數(shù)地址的語法規(guī)則,但是根據(jù)C++的標準,,類成員函數(shù)的指針仍然需要一個取地址符“&”,。解決方法很簡單,按照提示改成如下代碼即可:
CWzWindowsHook mouseHooker(&CWzWindowsHook::MouseMsgFilter);
十二,、wchar_t *類型與USHORT *的轉(zhuǎn)換錯誤
VC6的編譯器不支持wchar_t數(shù)據(jù)類型,,wchar_t實際上被定義成unsigned short,VC9的編譯器已經(jīng)支持wchar_t為內(nèi)置數(shù)據(jù)類型,,但是由一個編譯選項控制,,這個選項默認是打開的,也就是將wchar_t作為編譯器的內(nèi)置數(shù)據(jù)類型,。但是OLECHAR和WCHAR的定義仍然是unsigned short,,在VC6的編譯環(huán)境中,,兩者的指針都是USHORT *,相互賦值和做為函數(shù)參數(shù)傳遞沒有問題,,但是如果wchar_t作為編譯器的內(nèi)置數(shù)據(jù)類型,,那就意味著wchar_t *與OLECHAR *或WCHAR *是兩種不同類型的指針,相互賦值就會報編譯錯誤,,下面的信息就是一個典型的錯誤輸出:
f:\project\.....\shellpidl.cpp(290) : error C2664: 'MultiByteToWideChar' : cannot convert parameter 5 from 'USHORT *' to 'LPWSTR'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast 解決的方法就是使用C++的reinterpret_cast操作符或使用C-style強制轉(zhuǎn)換,,當然也可以在項目屬性設置中關閉前面提到的那個選項(這個偶美試過,不知道會不會有其它問題),。
本文來自CSDN博客,,轉(zhuǎn)載請標明出處:http://blog.csdn.net/orbit/archive/2008/11/28/3405309.aspx |
|
來自: iceberg_horn > 《Windows》