VC++6.0转到VS2008
来源:互联网 发布:一流程序员算法 编辑:程序博客网 时间:2024/05/17 07:07
刚从VC++6.0转到VS2008,用着好不习惯,网上找到一帖子,转给大家,希望会有帮助。
-------------------------------------------------------------------------------------------------------------------------------
1.MessageBox()
VC++6.0:MessageBox("Hello,World!");
VS2008:MessageBox(L"Hello,World!"); 或 MessageBox(TEXT("Hello,World!"));
2.Combo box内容添加方法
VC++6.0:Drop-Down List Box Control 的 Properties 中的 Data 用 Ctrl-Enter 输入
VS2008:更名为 Combo-Box Control ,并在右侧 Data 区域用 semicolons(即';')分隔输入
3.从.net开始就没有classwizard了,全部在属性窗口里了
属性窗口中有,闪电图标及右边的都是,包括事件,消息,虚函数重载,加入变量则是在类标上右击->添加变量……
4.消息映射
VS2005对消息的检查更为严格,以前在VC6下完全正常运行的消息映射在VS2005下编译不通过
a,ON_MESSAGE(message,OnMyMessage);
OnMyMessage返回值必须为LRESULT,其形式为:afx_msg LRESULT OnMyMessage(WPARAM, LPARAM);
如果不符合,则有错误提示:
error C2440: “static_cast”: 无法从“void (__thiscall CPppView::* )(WPARAM,LPARAM)”转换为“LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)”
error C2440: “static_cast”: 无法从“void (__thiscall CPppView::* )(void)”转换为“LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)”
b,在VS2005中,OnMyMessage返回值必须为BOOL,且含有一个 UINT 参数指出了命令ID,其形式为:afx_msg BOOL OnMyMessage(UINT);如果不符合,则有错误提示.
如在VS6中,OnMyMessage2的定义为afx_msg BOOL OnViewZoomBar()时亦可正常编译通过,但在VS2005下,有错误提示:
error C2440: “static_cast”: 无法从“BOOL (__thiscall CMainFrame::* )(void)”转换为“BOOL (__thiscall CCmdTarget::* )(UINT)”
error C2440: “static_cast”: 无法从“BOOL (__thiscall CMainFrame::* )(void)”转换为“BOOL (__thiscall CCmdTarget::* )(UINT)”
5.字符处理
在c中广泛使用的strcpy,strcat,strstr等等推荐使用更为安全strcpy_s,strcat_s,strstr_s等来代替.
6.数学函数检查
VS2005中,数学函数的参数检查更为严格,如pow(2, 45)会引起一个错误提示如下:
error C2668: “pow”: 对重载函数的调用不明确
d:\program files\microsoft visual studio 8\vc\include\math.h(575): 可能是“long double pow(long double,int)”
d:\program files\microsoft visual studio 8\vc\include\math.h(527): 或“float pow(float,int)”
d:\program files\microsoft visual studio 8\vc\include\math.h(489): 或“double pow(double,int)”
试图匹配参数列表“(int, int)”时
正确的使用为pow(2.0, 45)
7.更加符合C++标准
如在VS6中,在FOR循环中的循环变量的定义的作用域延伸到循环体外,VS2005则修正了这样的bug。
VC6:
for(int i=0;i<100;i++)f2();
for(i = 1;i<10;i++)f1();
而有VS2005中,第二句的i必须重新定义
--------------------------------------------------------------------------------------------------------------------------------------------
直接用Visual Studio 2008的打开VC6的工作区文件和项目文件(dsw和dsp),并将其升级为VS2008的解决方案格式和项目格式(sln和vcproj),VC9的编译器相对于VC6有了很大的变化,一些编译参数和链接参数被废弃(比如/map:line),有一些改变了名称,还有新增的选项,不过不用担心,升级过程会自动对其进行转换,最终都会得到一个正确的解决方案和VC项目文件,这个过程不会遇到太多的麻烦,问题都出在随后的编译过程中,下面就将我在移植的过程中遇到的问题和我的解决方法总结一下,希望对还在用VC6维护代码的朋友有所帮助。
一、_WIN32_WINNT 与 _WIN32_IE 设置冲突
StdAfx.cpp
c:\program files\microsoft sdks\windows\v6.0a\include\sdkddkver.h(217) : fatal error C1189: #error :
StdAfx.cpp通常是项目中第一个编译的文件,这个错误将导致编译无法继续进行。产生这个错误的原因是原因是_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
#endif
二、afximpl.h文件中的语法错误
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 ';'
合理调整stdafx.h中WINVER、_WIN32_WINNT、_WIN32_WINDOWS和_WIN32_IE的设置可以避免这个问题,将三个与Windows版本有关的环境变量设置为0x0501或更高版本,将IE版本的环境变量设置为0x0500以后的版本就可以解决这个问题。当然,考虑到与旧的VC6代码兼容,可以采用上一个问题中提到的最后一个解决办法,用_MSC_VER进行隔离。
三、 旧的CRT库和新的安全CRT库引起的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'
#pragma warning( disable : 4996 )
或者定义 _CRT_SECURE_NO_WARNINGS 压制这个告警(在stdafx.h中define或在项目属性中设置预处理符号,PreProcessor Definitions)。
四、“CWinApp::Enable3dControls”引起的C4996告警
CrpFileCrack.cpp
f:\project\.....\crpfilecrack.cpp(52) : warning C4996: 'CWinApp::Enable3dControls': CWinApp::Enable3dControls is no longer needed. You should remove this call.
通常向导生成的代码是:
#ifdef _AFXDLL
#else
#endif
这两个函数的调用是旧的MFC版本对新版本的操作系统特性的支持,在新的(那个时候是新的)Windows 95平台上要这样调用一下才能使用新的Windows 3D样式的控件,否则就是老的Win 3.2样子的控件。想当初喜欢OWL就是因为感觉它的控件比较“酷”,比如那个带底纹的对话框,菱形的checkbox,还有带图标的“OK”按钮,看到MFC作出来的灰灰的界面就觉得土,不过后来就知道MFC做界面也是很漂亮的,比如我做的。。。。,再打住。对于新的MFC版本来说已经不需要再调用这两个函数了,参考前面的方法,用_MSC_VER对其隔离就行了:
#if _MSC_VER <= 1200 // MFC 6.0 or earlier
#endif
五、.def文件引起的连接告警
.\ComFunc.def(4) : warning LNK4017: DESCRIPTION statement not supported for the target platform; ignored
一个典型的.def文件通常有以下内容:
LIBRARY
DESCRIPTION
EXPORTS
消除这个连接告警的方法就是从.def文件中删除DESCRIPTION描述信息,不过这个告警也不是什么大问题,不删也可以。另一个可能产生的连接告警是LNK4222,通常出现在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
出现这个告警的原因是旧的项目的.def文件通常这样定义ocx和com必需的四个导出函数:
EXPORTS
其中为这四个重要的导出函数指定了四个顺序号。Windows平台上通常用两种方式定位DLL文件中的导出函数,一种是根据导出函数名称,一种是根据顺序号,上学时曾经写过一个显示图片的程序,能处理大多数当时流行的图像格式文件,唯独jpeg格式的搞不定,有一次看到一个图像处理软件中包含了一个LoadJpeg.dll,很显然这个DLL是处理jpeg格式的图像文件的嘛,于是赶快用depends look了一下,顿时高喊:鬼啊~~~。原来这个depends竟然查不到导出函数的名字,后来才知道还有NONAME参数强制用顺序号定位导出函数,于是就常常弄个没有导出函数名字的DLL到处show。。。。嗯,又扯远了。话说为什么旧的系统要以此指定这四个导出函数的顺序号我就没有研究了,反正现在不需要指定了,只要将@1,@2之类的删除就行了,不过不删好像也没什么问题,它们会被自动忽略。
六、使用MFC的消息映射宏引起的编译错误
f:\project\.....\plusmaindlg.cpp(220) : error C2440: 'static_cast' : cannot convert from 'void (__thiscall CPlusMainDlg::* )(int,BOOL)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
f:\project\.....\crpfileopavdlg.cpp(87) : error C2440: 'static_cast' : cannot convert from 'LRESULT (__thiscall CCrpFileOpavDlg::* )(LPCTSTR,int)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
#define ON_MESSAGE(message, memberFxn) \
再看看新版本的ON_MESSAGE定义:
#define ON_MESSAGE(message, memberFxn) \
注意,函数类型没有变化,都是:
LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM);
类型的函数指针(CWnd以及派生类的类成员函数指针),区别之处是新的ON_MESSAGE宏使用C++的 static_cast 操作符代替了C类型的强制转换。产生这两个错误其实是因为用户没有按照ON_MESSAGE宏的约定声明和定义消息响应函数造成的,比如,对于某些不需要处理返回值的消息响应函数,用户通常这样声明和定义消息响应函数:
在头文件中声明:
afx_msg void OnFileProcess(WPARAM wParam,LPARAM lParam);
在源文件中实现:
void CCrpFileOpavDlg::OnFileProcess(WPARAM wParam, LPARAM lParam)
{
.......
}
或者更过分一些,直接指定为实际参数类型:
在头文件中声明:
afx_msg void OnFileProcess(LPCTSTR lpszMessage, int nPercent);
在源文件中实现:
void CCrpFileOpavDlg::OnFileProcess(LPCTSTR lpszMessage, int nPercent)
{
.......
}
旧版本的ON_MESSAGE使用了C类型的强制转换,宏解开后的代码后不会产生错误信息,但是改成对类型检查很严格的static_cast 操作符时就出问题了,因为通不过static_cast 操作符的检查。解决方法就是修改代码,同时吸取教训,普遍使用的方法并不一定就能约定俗成,一切还是要按照规矩来。
f:\project\.....\WzButton.cpp(74) : error C2440: 'static_cast' : cannot convert from 'UINT (__thiscall CWzButton::* )(CPoint)' to 'LRESULT (__thiscall CWnd::* )(CPoint)'
UINT (__thiscall CWzButton::* )(CPoint);
类型的类成员函数指针,其定义如下:
#define ON_WM_NCHITTEST() \
但是新版本变成了:
#define ON_WM_NCHITTEST() \
注意返回值类型由UINT改成了LRESULT,再加上static_cast的严格检查,所以就出错了。修改的方法就是将你的OnNcHitTest函数由:
afx_msg UINT OnNcHitTest(CPoint point);
改成:
afx_msg LRESULT OnNcHitTest(CPoint point);
不必太在意,这个不是你的错,不过,如果你要维护一个老的界面库(通常很多控件的subclass都会用到ON_WM_NCHITTEST),改起来还是很痛苦地,不扯了,继续下一个。
七、statreg.cpp 和 atlimpl.cpp 的废弃(obsolete)问题
StdAfx.cpp
statreg.cpp is obsolete. Please remove it from your project.
atlimpl.cpp is obsolete. Please remove it from your project.
因为老的ATL向导生成的代码通常在stdafx.cpp文件中添加以下代码:
#ifdef _ATL_STATIC_REGISTRY
#include <statreg.h>
#include <statreg.cpp>
#endif
#include <atlimpl.cpp>
根据提示删除#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++编译器不再支持默认类型的变量定义
错误现象是:
f:\project\.....\WzCheckBox.cpp(464) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
产生这个错误的原因是程序中出现了这样的代码:
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(i < 120)
{
}
在VC6的编译器中,这样的代码是没有问题的,因为VC6的编译器为了兼容旧的Microsoft C/C++编译器,没有严格按照C++标准执行,但是从VC7开始,VC的编译器开始遵守C++标准,所以就会出现“变量i没有定义的错误”。解决的方法也很简单,按照Jim Hyslop 和 Herb Sutter的经典对话系列的第四篇中的方法,改成如下就可以了:
int i;
for(i = 0; i < 120; i++)
十、字符串函数的返回值问题
TCHAR *cp = _tcschr( pszPath, _T('\\') );
//使用*cp,可以通过cp指针修改pszPath的内容
这其实是一个“漏洞”,因为如果pszPath是const char(TCHAR) *字符串,那么就表示它不希望修改字符串的内容,但是调用strchr(_tcschr)函数后就可以通过cp指针修改其内容了,这岂不荒谬?所有在新版本的CRT库中,这几个函数的返回值都改成const char *,这就会导致上面的代码产生编译错误。建议的修改方式是改成如下方式:
const TCHAR *cp = _tcschr( pszPath, _T('\\') );
//不能再通过cp指针修改pszPath的内容
但是这样修改可能对代码的影响比较大,比如下面的代码:
TCHAR buf[256]; //局部缓冲区
......
TCHAR *cp = _tcschr( buf, _T('\\') );
//作为局部缓冲区(非const),希望通过cp修改buf的内容
这种情况怎么办呢?对了,C++还有个const_cast操作符,这时就可以排上用场了:
TCHAR *cp = const_char<TCHAR *>(_tcschr( buf, _T('\\') ));
不过上面的方法要慎用,除非确定buf是非const的,否则最好老老实实地修改代码。
十一、类成员函数指针做为函数参数的“C3867”错误
typedef
// A hook used in customization sheet to filter keyboard/mouse events
class CWzWindowsHook
{
private:
public:
旧的遗留代码存在这样的用法:
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继承来了函数名即是函数地址的语法规则,但是根据C++的标准,类成员函数的指针仍然需要一个取地址符“&”。解决方法很简单,按照提示改成如下代码即可:
CWzWindowsHook mouseHooker(&CWzWindowsHook::MouseMsgFilter);
十二、wchar_t *类型与USHORT *的转换错误
f:\project\.....\shellpidl.cpp(290) : error C2664: 'MultiByteToWideChar' : cannot convert parameter 5 from 'USHORT *' to 'LPWSTR'
解决的方法就是使用C++的reinterpret_cast操作符或使用C-style强制转换,当然也可以在项目属性设置中关闭前面提到的那个选项(这个偶美试过,不知道会不会有其它问题)。
- VC++6.0转到VS2008
- VC++6.0转到VS2008常出现的错误及解决方案
- VC++6.0转到VS2008常出现的错误及解决方案
- VC++6.0-->VS2008:
- VC6.0 工程转到VS2008
- vc++6.0,vc++2008,vs2008的关系
- vs2008 ,右键转到定义,弹出“未定义符号
- VS2008转到定义切换时运行卡死
- VC++6.0与VS2008的区别
- VC++6.0 VS2008遇到的问题总结
- VC++ 6.0以及VS2008 UNICODE工程设置
- VC 6.0 通过ADO 远程连接VS2008
- VC++6.0转换至VS2008问题实例
- 一步步教你从VC 6.0 转到 Visual Studio 编写C程序
- 将项目从VC6转到VC Express
- vs2008 vc 目录
- VS2008 VC++ XML操作
- VS2008转到定义转到元数据,无法定位到指定的类方法
- 建立一个别人永远删不掉的管理员用户
- C#实现P2P应用程序
- 无线模块调试总结
- Tomcat_曹建波的个人总结(第一次课)
- JavaScript面向切面编程
- VC++6.0转到VS2008
- uva 11178 - Morley's Theorem(训练指南)
- http协议_齐禄禄的个人总结(第二次课)
- Java Dao工厂设计模式
- Servlet开发基础_常瑞鹏的个人总结(第三次课)
- 易拓开发经验分享(一)
- HttpServletResponse应用_侯子腾的个人总结(第四次课)
- 深入浅出MFC学习笔记:MFC六大关键技术仿真之动态生成
- java基础之类继承