自 Visual C++ 6.0 以来 ATL 7.0 和 MFC 7.0 中的重大更改[转]
自 Visual C++ 6.0 以来 ATL 7.0 和 MFC 7.0 中的重大更改
自 Visual C++ 6.0 以来 ATL 7.0 和 MFC 7.0 中的重大更改
自从 Visual C++ 6.0 以来,已经对 ATL 和 MFC 库进行了许多改进。这些更改中某些可能会破坏现有的代码,下面列举了一些示例:
- DLL 不兼容性(ATL 和 MFC)
- ATL 模块类 (ATL)
- 字符串转换 (ATL)
- 从 BSTR 转换到 CString(ATL 和 MFC)
- CException 现在是抽象基类 (MFC)
- CComEnumImpl::Skip 更改 (ATL)
- CWnd::DestroyWindow 断言 (MFC)
- LNK2001 无法解析的外部符号错误 (MFC)
- Boolean 表达式现在类型为 bool,而非 BOOL (MFC)
- CColorPropPage 和 CFontPropPage 已被移除 (MFC)
DLL 不兼容性
作为 Visual C++ .NET 2003 的一部分提供的 ATL 和 MFC DLL 文件已分别被重命名为 ATL71.dll 和 MFC71.dll。
Visual C++ .NET ATL 和 MFC 类与早期版本的相同类之间没有二进制兼容性,因此任何使用 mfc42.dll 生成的源代码必须用 Visual Studio .NET 重新生成。应用程序使用的任何 DLL 或 LIB 文件也必须用 Visual Studio .NET 重新生成。
例如,使用 Visual C++ 6.0 生成的、包含导出函数(该函数将 CString 用作参数)的库在与 Visual C++ .NET 项目链接时将产生无法解析的外部链接。
ATL 模块类
ATL 3.0 提供了 CComModule 类。在 ATL 7.1 中,以前由 CComModule 提供的功能由若干新类处理。有关更多信息,请参见 ATL 模块类。
字符串转换
Visual C++ 6.0 中 ATL 3.0 和 ATL 3.0 以前的 ATL 版本中,使用 atlconv.h 中的宏的字符串转换始终是使用系统 (CP_ACP) 的 ANSI 代码页执行的。从 Visual C++ .NET 中的 ATL 7.0 开始,字符串转换将使用当前线程的默认 ANSI 代码页执行,除非定义了 _CONVERSION_DONT_USE_THREAD_LOCALE(此情况下,如以前一样使用系统的 ANSI 代码页)。
请注意,字符串转换类(如 CW2AEX)使您得以将用于转换的代码页传递给它们的构造函数。如果未指定代码页,这些类使用与宏相同的代码页。
有关更多信息,请参见 ATL 和 MFC 字符串转换宏。
CException 现在是抽象基类
CException 在 Microsoft 基础类库中是所有异常的基类。因为 CException 现在是抽象基类,所以您不能直接创建 CException 对象;必须创建派生类的对象。如果您确实直接创建了对象,将会收到错误。有关更多信息,请参见 CException。
从 BSTR 转换到 CString
在 Visual C++ 6.0 中,使用下面的代码是可以接受的:
BSTR bstr = SysAllocString(L"Hello"); CString str = bstr; SysFreeString(bstr);
对于 Visual C++ .NET 下的新项目,这将在 ANSI 版本下导致下面的错误:
error C2440: 'initializing' : cannot convert from 'BSTR' to 'ATL::CStringT<BaseType,StringTraits>'
现在有 CString 的 UNICODE 和 ANSI 版本(CStringW 和 CStringA)。若要标记任何由隐式转换导致的不必要的系统开销,采用反向类型(如带 UNICODE 参数的 CStringA,或者带 ANSI 参数的 CStringW)的构造函数现在在 stdafx.h 中被使用下面的项标记为显式的:
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
若要避免此错误,请执行下列操作之一:
- 使用 CStringW 以避免转换:
BSTR bstr = SysAllocString(L"Hello"); CStringW str = bstr; SysFreeString(bstr);
- 显式调用该构造函数:
BSTR bstr = SysAllocString(L"Hello"); CString str = CString(bstr); SysFreeString(bstr);
- 从 stdafx.h 中移除
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
行。
CComEnumImpl::Skip 更改
在 ATL 7.0 之前的版本中,CComEnumImpl::Skip 方法不能为输入值 0 返回正确的错误代码。它还会以不一致的方式处理大的输入值。这些行为在 ATL 7.0 中已被修复。
CWnd::DestroyWindow 断言
当 CWnd::DestroyWindow 中显示工具提示时,会发生断言错误。因此,在 MFC 7.0 中,下列成员变量被从 AFX_THREAD_STATE 移到 AFX_MODULE_THREAD_STATE:
- CToolTipCtrl* m_pToolTip
- CWnd* m_pLastHit
- int m_nLastHit
- TOOLINFO m_lastInfo
- int m_nLastStatus
- CControlBar* m_pLastStatus
LNK2001 无法解析的外部符号错误
当调用采用 wchar_t 类型的静态库或 DLL 中的函数时(请注意,BSTR 和 LPWSTR 解析为 wchar_t*),可能会遇到“LNK2001 无法解析的外部符号错误”。
此错误由 /Zc:wchar_t 编译器选项引起,默认情况下此选项在新的 MFC 项目中设置为打开。此选项使编译器将 wchar_t 当作本机类型。在 Visual C++ .NET 以前版本中,wchar_t 被当作 unsigned short。
如果主项目和库不使用 /Zc:wchar_t 的相同设置,这将导致函数签名不匹配。若要避免此问题,请使用 /Zc:wchar_t 编译器选项重新生成该库,或使用“属性页”对话框中“语言”属性页上的“将 wchar_t 视为内置类型”设置在主项目中将该选项关闭。
Boolean 表达式现在类型为 bool,而非 BOOL
请看下面的类:
class CMyClass : public CObject { BOOL bFlag; void Serialize (CArchive& ar)) { if (ar.IsStoring()) ar << (bFlag != FALSE); // breaking change else ar >> bFlag; } };
在 Visual C++ .NET 之前,表达式 bFlag != FALSE
计算为 BOOL 并写入四个字节;在 Visual C++ .NET 中,它计算为 bool 并写入一个字节。这意味着用不同的编译器版本编译的程序可能会生成相互不兼容的数据文件。
若要避免该问题,请将表达式转换为 BOOL:
ar << (BOOL)(bFlag != FALSE);
请参见
升级程序 | ATL 和 Visual C++ 版本号 | MFC 和 Visual C++ 版本号 | ATL 2.1 版的改动 | MFC 版本中的改动
CColorPropPage 和 CFontPropPage 已被移除
在以前版本的 MFC 中,ActiveX 控件通过分别指定 GUID CLSID_CColorPropPage 或 CLSID_CFontPropPage 为颜色或字体属性显示属性页。这些 GUID 指向类 CColorPropPage 和 CFontPropPage,现在不再实现它们。改用 GUID CLSID_StockColorPage 和 CLSID_StockFontPage。它们是通过 msstkprp.dll 实现的,因此您必须用应用程序重新发布该 DLL。
原文地址 http://msdn