INFO: MFC 3.x转换为4.0的常见问题

发表于:2007-07-01来源:作者:点击数: 标签:
本文适用于: 包含于: - Microsoft Visual C++, 32-bit Edition, versions 4.0, 4.1, 4.2, 5.0 的微软基本类库(Microsoft Foundation Classes,MFC)。 概述: 本文列举了当你想把用MFC 3.x(这个MFC包含在Visual C++ 2.x中)编写的应用程序port为利用MFC 4


本文适用于:

包含于: - Microsoft Visual C++, 32-bit Edition, versions 4.0, 4.1, 4.2, 5.0 的微软基本类库(Microsoft Foundation Classes,MFC)。

概述:

本文列举了当你想把用MFC 3.x(这个MFC包含在Visual C++ 2.x中)编写的应用程序port为利用MFC 4.0(这个MFC包含在Visual C++ 4.0)工作时,最常遇到的一些bug问题,和其他问题。

一般问题

1.MFC不再预先注册Window 类。

在4.0以前的版本中,MFC预先注册了四个窗口类(WNDCLASS),正如MFC Technical Note number 1中所说明的那样。这些窗口类是AfxWnd, AfxFrameOrView, AfxMDIFrame,和AfxControlBar。大多数防止产生一个应用程序的多个实例的代码(如ONETIME样本)都依赖于这些类。现在,在4.0版本中,在创建相应类型的窗口之前,这些类是不会被注册的。如果MFC追踪功能被打开,GetLastError会将值0x57F (ERROR_WNDCLASS_DOES_NOT_EXIST)返回到调试输出窗口。基于一个自定义WNDCLASS(填满来自MFC窗口类的信息)的窗口可能会不能显示和发送窗口创建失败的消息。

从4.0版本开始,当用RegisterClass 或AfxRegisterClass注册窗口类时,你需要提供所有必要的信息。不要靠::GetClassInfo去找回MFC窗口类的类值。

如果要知道更多的信息,请看MFC Technical Note 1和下列Microsoft Knowledge Base中的文章。

ARTICLE-ID: Q140596

TITLE: MFC 4.0 No Longer Pre-Registers Window Classes

ARTICLE-ID: Q141752

TITLE: SAMPLE: Limiting 32-bit Applications to a Single Instance

2.BUG: CFormView上的第一个控件,在OnInitialUpdate执行之前获得OnSetFocus。

如果在OnSetFocus中有涉及到直到调用基本类OnInitDialog 时才被子类化的CWnd对象的代码时,就会发生问题。当任何其他句柄作为获得焦点的控件结果被调用时,也会发生这一问题。例如,当单选按钮获得焦点时,会产生一个BN_CLIKED。如果想得到其他信息和工作区,请看下列Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q142274

TITLE: FIX: Assertion Failure When Handling xN_SETFOCUS in

CFormView

 

3.CWinApp::m_templateList不在存在了:

CWinApp 的m_templateList成员变量在4.0版本以前的MFC中并没有说明,但却经常使用,被称为porting issue。微软建议使用GetFirstDocTemplatePosition()和GetNextDocTemplate()成员函数访问应用程序的模板。

要想得到更多的信息,请看下列Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q106455

TITLE: How to Acquire a List of All CDocument Objects

 

4.BUG:CString +=操作符可能被空字符串中断。

导致这一bug的特定事件序列是复杂的。在MFC源代码中有一个bug,当+=操作符使用一个空字符串时,它不能作出正确地处理。

要想得到更多的信息,请看下列Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q142385

TITLE: FIX: Using CString::operator+= May Cause an Aclearcase/" target="_blank" >ccess Violation

5.BUG:当滚动条被编程滚动时,WM_xSCROLL 消息的OnWndMsg事件中断。

在MFC 4.0中加入了新的代码,用于将完整的32位地址(如果有)传送到OnxScroll句柄,因为WM_xSCROLL消息只能打包16位的地址信息。不幸的是,不论什么时候只要应用程序用SendMessage向自己发送一个WM_xSCROLL消息来编程滚动滚动条,新加入的代码就会中断。

要想得到更多的信息,请看下列Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q147684

TITLE: FIX: Sending WM_xSCROLL Message Causes Invalid ASSERT

6.BUG:现在OnInitMenuPopup在返回前删除菜单临时 map。

在4.0版的MFC中,在CWnd::OnInitMenuPopup中加入了对AfxLockTempMaps和AfxUnlockTempMaps的调用。当调用AfxUnlockTempMaps时,MFC的临时对象映射引用计数器将变为零,使得所有的临时MFC对象都被删除。当对OnInitMenuPopup的调用返回时,被传送到OnInitMenuPopup 的CMenu指针(这是一个临时指针)将是无效的。

要想得到更多的信息,请看下列Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q141532

TITLE: FIX: OnInitMenuPopup Deletes Temporary Objects

7.文档化的CRuntimeClass::m_pfnConstructObject现在是m_pfnCreateObject.

在4.0版以前的MFC中,m_pfnConstructObject是CRuntimeClass的一个文档化成员变量,但现在为了反映参数和返回值的改变,名字也相应作了更改。包含在Visual C++ 4.0中的文档并没有进行相应的更新,错误地引用了旧的函数名。

8.BUG:缺省的基于对话框的应用程序在Win32s中不工作。

当AppWizard产生一个基于对话框的应用程序时,它为主对话框使用一个DIALOGEX资源。但是,Win32s不支持DIALOGEX资源。结果,在Win32s中,对话框看起来有点不对。通过从对话框编辑器中去掉WS_EX_APPWINDOW类型和在.rc文件中将DIALOGEX声明改为DIALOG声明,可以对这个问题进行修正。

要想得到更多的信息,请看Visual C++ Readme文件和下列Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q138971

TITLE: BUG: Default Dialog-Based Application Doesn@#t Work in Win32s

CPropertySheet

现在,许多CPropertySheet的MFC实现已经被更改用来包装Windows Property Sheet通用控件。格式和尺寸上有一些改变,但更重要的是,如果代码使用了CPropertySheet的任何私有MFC实现,当类的大多数未文档化成员不在那时,代码就会中断。

9.CPropertySheet总是将它的字体变为缺省字体。

即使在资源编辑器中改变了属性页的字体,在运行时属性页也会以系统字体显示。如果有必要改变字体,在OnInitDialog中调用SetFont();然后使用合适的MoveWindow()调整页的大小并移动,调整页上所有控件的大小。还有,无论什么时候,当一个页被激活时,属性也就会恢复到原来的大小,因此,有必要调整页的大小以响应标签控件上的单击。

要想得到更多的信息,请看下列Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q142170

TITLE: SAMPLE: PRPFONT - How to Set CPropertySheet Fonts

10.调用一个基本类后应该修改OnInitDialog中的属性页。

在CPropertySheet::OnInitDialog期间,属性页的大小被调整,四个标准按钮(OK, Cancel, Apply, 和 Help)被隐藏在非模态属性页的底部。调用基本类以后在OnInitDialog中修改页的大小或定制用户化的四个属性页按钮是合适的。在以前版本的MFC中,在OnCreate中隐藏一些模态属性页显示的按钮是很平常的事。现在,通过在PROPSHEETHEADER 结构 CPropertySheet::m_psh中修改类型,可以很容易地去掉这些按钮。

要想得到更多的信息,请看下列Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q140585

TITLE: PRB: Resizing CPropertySheet in OnInitDialog Does Not Work

ARTICLE-ID: Q141039

TITLE: How to Hide the Apply Button in CPropertySheet

11.在Windows 95,CPropertySheet::DoModal()导致一个first chance异常。

因为属性页设置需要对话框资源中的类型,在Windows 95上将发生一个first chance异常,。操作系统需要对此进行控制,因此消息可能被忽略。如果你用一个try/catch(...)块把DoModal()调用包起来,企图自己解决异常,那么你会得到一个堆栈错误。

12.现在属性页有一个最小化的宽度。

CPropertySheet窗口的最小化宽度是四个按钮的大小,这四个按钮将会沿着一个模态属性页的底部向上显示。这一宽度甚至也应用于非模态属性页,在这种属性页中并不沿着底部显示四个按钮。

DLLs

13.在DLL启动期间,不能创建MFC线程。

尽管不是一个好办法,在以前版本的MFC中,在MFC DLL启动期间创建一个线程是可能的。这包括在DLLMain,DLL中的RawDllMain,InitInstance或任何被他们调用的函数中调用AfxBeginThread 或 CWinThread::CreateThread。由于MFC线程启动代码的同步及DLL RPOCESS ATTACH和DLL THREAD ATTACH期间在DllMain的阻塞,将不再允许这样做。 。当被应用程序调用的MFC 4.0 DLLS试图这样做时,将会被挂起。

要想得到更多的信息,请看下列Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q142243

TITLE: PRB: Cannot Create an MFC Thread During DLL Startup

14.使用共享库中MFC的正常DLLs,在输出函数中需要AFX_MODULE_STATE。

以前,USRDLL模型要求MFC静态地链接到DLL。现在从一个正常(Regular)DLL(_USRDLLs的新概念)动态链接到Mfc40.dll是可能的。值得注意的是,为了将一个_USRDLL转化为一个“使用共享库中MFC的正常DLL”,你要确保正确地管理模块状态信息。下面一行代码:

AFX_MANAGE_STATE(AfxGetStaticModuleState());

应该被加到任何从操作MFC对象的DLL输出的函数的开始部分。

如果没有适当地转变模块状态,就可能发生下列问题:

由于丢失资源,在一个DLL中创建对话框和窗口时失败。
调用错误应用程序对象,导致堆栈溢出或不可预知的结果。
不可知的运行时间类信息.
Bad window-to-MFC 对象处理映射连接.
要想得到更多的信息,请看MFC Technical Note 58 (TN058)和下列Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q140850

TITLE: How to Convert DLLTRACE to Use MFC in Shared Library

15.BUG:DoModal可能在MFC扩展DLLs中失败。

当MFC 4.0创建一个对话框时,它将当前实例的句柄传递给::CreateDialogIndirect Windows API椪飧?/FONT>API为DLL产生对话框而不是资源句柄。MFC已经从正确的扩展DLL装入了对话框的模板。但是,Windows将会在实例句柄指定的.exe 文件中寻找任何模板上指示的其他资源。如果他们在DLL中, Windows将找不到他们,对话框的创建将会失败。为解决这个问题,应该在任何对DoModal的调用之前,转换当前实例的句柄。其他资源包括对话框菜单,自定义控件,或对话框上的图标。

要想得到更多的信息,请看下列Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q147384

TITLE: FIX: Icons, Bitmaps, & Menus Not Displayed in an AFXDLL

Dialog

16.CStatusBar和CToolBar

像CPropertySheet一样,这些类现在也是用来包装Win32通用控件功能的。依赖或修改这些类的私有非文档实现的代码,在为MFC 4.0编译时,都可能中断。这两个通用控件比以前的缺省MFC实现支持更大范围的通用定制,而且它们不通过重要的覆盖MFC 源就能完成诸如创建调色板条或制作调整大小的工具条之类的工作。如果需要,这两个类的旧的作为COldToolBar和COldStatusBar类的实现仍然可用。这些实现可以在OLDBARS样本对象中找到。

17.CToolbar::SetSizes和按钮的尺寸设置

现在,工具条要求按钮的宽度至少比图像的尺寸大7个像素。Visual C++ 4.0中的文档没有做相应的更新,是错误的。MFC version 4.0用来检验SetSizes中正确参数的ASSERT也不是原来的6。还有关于工具条,按钮,和图像尺寸的一些其他限制,但是这些限制已经被MFC源中的ASSERT声明包括了并且从MFC 3.x以来一直没有改变。

要想得到更多的信息,请看下列Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q141444

TITLE: DOC: Incorrect Documentation for CToolBar::SetSizes()

CFileDialog

18.不需要替换MFC提供的CFileDialog 钩子(hook)过程。

MFC总是在CFileDialog对象构建期间为Open File Dialog指定自己的钩子过程(_AfxCommDlgProc),使它能将对话框的通知正确地发送到正确的句柄。对于MFC 4.x,这个hook过程用来将CFileDialog对象的子类到Open File Dialog窗口。如果钩子过程被替换了,这个子类过程不会发生,因此任何使用CFileDialog或嵌在它上面的控件变量(如果它是一个窗口)的企图都将失败。

19.CFileDialog总是浏览器对话框窗口的产物。

当你使用浏览器风格的CFileDialog(在Windows 95中,缺省情况就是这样)时,MFC采用用户化的浏览器模型。这意味着,对File对话框的定制改进,被包含在一个分离的模板上,这个模板被加到标准浏览器对话框周围。在MFC 4.0中,实际的CFileDialog窗口是主文件共用对话框的一个子对话框,即使你没有提供一个模板来用户化这个对话框。因此,如果你需要通过移动或隐藏控件来改变标准浏览器接口,就要在所有对Explorer控件的GetDlgItem()调用的前面加上GetParent()作为前缀。例如,表达式:

GetParent()->GetDlgItem(IDOK)

将返回一个指向浏览器对话框中Open/Save按钮的指针。然而,并不建议这样做,因为如果将来浏览器的设计改变了,那些依赖标准浏览器对话框控件详细资料的代码将会中断。

可以通过去掉OFN_EXPLORER类型改变缺省设置。

要想得到更多的信息,请看下列Microsoft Knowledge Base文章:

ARTICLE-ID: Q131225

TITLE: PRB: CFileDialog::DoModal() Does Not Display FileOpen Dialog

19.CFileDialog的成员函数GetFileName和GetFileTitle互相颠倒了。

在MFC4.0中,对于文件C:\Article.txt:

CFileDialog::GetFileName返回Article.txt。

CFileDialog::GetFileTitle返回Article。

以前版本的MFC返回的正好相反。这些函数已经变为以和同名Win32 API函数相似的方法工作。然而,包含在Visual C++ 4.0中的文档并没有做相应的更新,是错误的。

要想得到更多的信息,请看Visual C++ Readme文件和下列Microsoft Knowledge Base中的文章。

ARTICLE-ID: Q142203

TITLE: DOCERR: GetFileTitle() & GetFileName() Docs Are Switched

MFC ODBC

20.BUG:带CLongBinary域的Dynasets抛出异常。

使用带CLongBinary-bound域的dynaset recordsets 的MFC ODBC应用程序能在Visual C++ 2.x中工作,但现在Visual C++ 4.0中,当打开recordset时,它抛出一个异常。该异常是从CRecordset::InitRecord抛出的.

要想得到更多的信息,请看下面Microsoft Knowledge Base中的文章:

ARTICLE-ID: Q141303

TITLE: FIX: Dynasets w/ CLongBinary Fields Throws Incorrect

Exception

MFC OLE

21.不再有Mfcans32.dll,因此MFC应用程序中的OLE函数需要Unicode变量。

在MFC 3.x中,当调用OLE接口时,使用一个特殊的DLL(Mfcans32.dll)在Unicode和MBCS之间自动转换。MFC 4.0并不使用这个DLL;而是直接和Unicode OLE接口对话。为了处理这一改变,现在MFC应用程序必须向OLE函数传送参数的正确类型棗不管是Unicode还是MBCS。MFC 4.0已经提供了许多宏,以使这一工作更容易。

为了得到更多的信息,请看MFC Technical Note 59。

参考文献

你可以在Visual C++ CD-ROM的如下目录中找到Visual C++ InfoView中的参考MFC Technical Notes:

Visual C++ Books

MFC 4.0

MFC Technical Notes

Visual C++ Readme可以在\Msdev\Vcread.wri文件中找到,或在以下的Visual C++ InfoView中:

README for Microsoft Visual C++ Version 4.0

Microsoft Foundation Classes (MFC)"


原文转自:http://www.ltesting.net