代码改变世界

收到 wincore.cpp 中一个 " ASSERT " BUG: 当 MFC 应用程序 Visual C++ 中 MFC 规则 DLL 中调用函数声明

2007-07-02 14:50  flyingfish  阅读(6106)  评论(0编辑  收藏  举报

今日将VC2005写的DLL的源码转到VC6时,弹出对话框时,报告:

---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Assertion Failed!

Program: D:\工作目录\Topology VC6.0\Bin\Test_Topology.exe
File: wincore.cpp
Line: 884

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

(Press Retry to debug the application)
---------------------------
终止(A)   重试(R)   忽略(I)  
---------------------------

image

经查,好像是VC6的Bug。

http://support.microsoft.com/kb/194300/zh-cn

收到 wincore.cpp 中一个 " ASSERT " BUG: 当 MFC 应用程序 Visual C++ 中 MFC 规则 DLL 中调用函数声明

 

我的总结:在调用Dll中资源时尽量用下边的语句代替AFX_MANAGE_STATE(AfxGetStaticModuleState());可以绕过这个错误。

    //AFX_MANAGE_STATE(AfxGetStaticModuleState());
    HMODULE hDLL=GetModuleHandle("SpatialReference.dll");
    HINSTANCE hEXE=AfxGetResourceHandle();
    AfxSetResourceHandle((HINSTANCE)hDLL);
    //函数返回之前:
    // AfxSetResourceHandle(hEXE);

 

微软网站的解决办法是:

症状

当 MFC EXE SDI / MDI 应用程序上下文中的命令处理程序调用 MFC 规则 DLL, 创建模式对话框, MFC 中导出函数以下断言可能触发:

ASSERT wincore.cpp 行 884 中
ASSERT wincore.cpp 行 883 中

如果忽略, 应用程序行为通常断言。 EXE 和规则 DLL 必须动态链接到 MFC。

回到顶端

原因

当父未显式指定模式对话框, MFC PreModal() 调用中确定与调用到 CWnd::GetSafeOwner_() 父。该调用返回路由框架 (AfxGetThreadState() "-> m_pRoutingFrame)。 m_pRoutingFrame 分配命令处理程序中。 [ 请参阅 CFrameWnd::OnCmdMsg() 中 CPushRoutingFrame ]
EXE, 到框架窗口是 EXE 中命令处理程序中设置路由框架。 因为线程状态是 EXE 和 DLL, 中相同 AfxGetThreadState() "-> m_pRoutingFrame 返回 EXE 框架窗口。 临时柄映射是 DLL, 为 CDialog::PreModal() 调用当调用 CWnd::FromHandle(::GetActiveWindow()) 中路由框架中创建临时 CWnd。 此断言, CWnd::AssertValid(), 中由事实路由框架临时 CWnd 的规则 DLL 临时柄映射中存在不匹配。
此问题影响的规则 DLL, 其中 CWnd::GetSafeOwner_() 称为上下文中命令处理程序中创建的所有模式窗口。 CWnd::GetSafeOwner_() 称为模式窗口的创建过程。 这包括 MFC 消息框、 OLE 属性页、 CDatabase::Connect、 对话框、 属性页和 OLE 忙对话框中。 请注意因为 CWnd::GetSafeOwner_() 是不调用在此上下文中, 此问题不影响无模式窗口不。

回到顶端

解决方案

一个解决办法是: 暂时在是 DoModal() 调用期间设置 AfxGetThreadState() "-> m_pRoutingFrame 到 NULL。 可以使用以下代码:

class tempRoutingFrame {

   CFrameWnd* m_pFrame ;

public:

   tempRoutingFrame(CFrameWnd * pWnd= NULL)
   {
      // Save current value
      m_pFrame = AfxGetThreadState()->m_pRoutingFrame;
      // Set to value passed in. NULL by default.
      AfxGetThreadState()->m_pRoutingFrame = pWnd;
   }
   ~tempRoutingFrame()
   {
      // Restore m_pRoutingFrame to original value.
      AfxGetThreadState()->m_pRoutingFrame = m_pFrame;
   }

};

extern "C" void __declspec(dllexport) TestFunction();

void TestFunction()
{
   AFX_MANAGE_STATE(AfxGetStaticModuleState())
   #ifdef _DEBUG
   // Workaround for ASSERT in WINCORE.CPP 884 (CWnd::AssertValid)
   tempRoutingFrame rframe;
   #endif
   CMyDialog dlg;
   dlg.DoModal();
}
				
其他解决办法, 对对话框和属性表, 而言是要明确设置对话框中的父级如下:
void TestFunction()
{
   AFX_MANAGE_STATE(AfxGetStaticModuleState())
   CMyDialog dlg(AfxGetMainWnd());
   dlg.DoModal();
}
				

回到顶端

状态

Microsoft 已确认这是了本文开头列出 Microsoft 产品中存在错误。
早在 Visual Studio 6.0 Service Pack 3 中得到解决此错误。 有关 VisualStudio, ServicePack 详细信息请单击下列文章编号, 查看 Microsoft 知识库文章中文章:

194022 (http://support.microsoft.com/kb/194022/) Visual Studio 6.0 服务包, 什么, 其中, 为什么

194295 (http://support.microsoft.com/kb/194295/) 如何判断安装 VisualStudio 服务包

回到顶端

更多信息

复现行为的步骤

1.使用应用程序向导创建常规 MFCDLL 项目。

2.确定和取消按钮和一个编辑控件, 创建新的对话框框资源。

3.创建对于从 CDialog 派生对话框类。 命名该类 CMyDialog。

4.mydialog.cpp 中添加下列函数:

extern "C" void __declspec(dllexport) TestFunction();

void TestFunction()
{
   AFX_MANAGE_STATE(AfxGetStaticModuleState());
   CMyDialog dlg;
   dlg.DoModal();
}
					

5.生成 DLL。

6.创建默认应用程序向导应用 EXE 项目。

7.使用以下替换 OnAppAbout 函数:

extern "C" void __declspec(dllimport) TestFunction();

void CMyTestApp::OnAppAbout()
{
   TestFunction();
}
					

8.添加导出库向第 6 步中创建项目第 5 步中创建。

9.将步骤 5 到 Debug 文件夹为第 6 步中生成应用程序中生成 DLL。

10.生成并运行。

11.在 帮助 菜单上, 单击 关于 。

结果 : ASSERTS wincore.cpp, 中 883 和 884 行被触发。

回到顶端

参考

MFC 模块状态实现 TN058: