Microsoft KB Archive/194300

= BUG: You receive an "ASSERT in wincore.cpp" assert when an MFC application calls a function in MFC regular DLL in Visual C++ =

Article ID: 194300

Article Last Modified on 11/21/2006

-

APPLIES TO

 Microsoft Foundation Class Library 4.2, when used with:  Microsoft Visual C++ 6.0 Enterprise Edition

 Microsoft Visual C++ 6.0 Professional Edition

 Microsoft Visual C++ 6.0 Standard Edition 

-

<div class="notice_section">

This article was previously published under Q194300

<div class="symptoms_section">

SYMPTOMS
When an MFC EXE SDI/MDI application in the context of a command handler calls an exported function in MFC regular DLL, which creates a MFC modal dialog box, the following asserts may be triggered:

ASSERT in wincore.cpp line 884

ASSERT in wincore.cpp line 883

If the asserts are ignored, the behavior of the application is normal. The EXE and regular DLL must be dynamically linked to MFC.

<div class="cause_section">

CAUSE
When a parent is not explicitly specified for a modal dialog box, MFC in the PreModal call determines the parent with a call to CWnd::GetSafeOwner_. This call returns the routing frame (AfxGetThreadState->m_pRoutingFrame). m_pRoutingFrame is assigned in a command handler. [See CPushRoutingFrame in CFrameWnd::OnCmdMsg].

The routing frame is set in the command handler in the EXE, to a frame window of the EXE. Because the thread state is the same in the EXE and the DLL, AfxGetThreadState->m_pRoutingFrame returns the EXE frame window. A temporary CWnd is created, in the temporary handle map of the DLL, for the routing frame in the CDialog::PreModal call when calling CWnd::FromHandle(::GetActiveWindow). This assert, in CWnd::AssertValid, is caused by the fact that routing frame does not match the temporary CWnd present in the temporary handle map of the regular DLL.

This problem affects all modal windows that are created in a command handler in the context of a regular DLL, where CWnd::GetSafeOwner_ is called. CWnd::GetSafeOwner_ is called during the creation of modal windows. This includes MFC message boxes, OLE property sheets, CDatabase::Connect, dialogs boxes, property sheets, and OLE busy dialog boxes. Note that this problem does not affect modeless windows because CWnd::GetSafeOwner_ is not called in this context.

<div class="resolution_section">

RESOLUTION
One workaround is to temporarily set AfxGetThreadState->m_pRoutingFrame to NULL for the duration of the DoModal call. The following code can be used: 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; } Another workaround, in the case of dialog boxes and property sheets, is to explicitly set the parent of the dialog box as follows: void TestFunction {  AFX_MANAGE_STATE(AfxGetStaticModuleState) CMyDialog dlg(AfxGetMainWnd); dlg.DoModal; }

<div class="status_section">

STATUS
Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.

This bug was corrected in Visual Studio 6.0 Service Pack 3. For more information about Visual Studio service packs, click the following article numbers to view the articles in the Microsoft Knowledge Base:

194022 Visual Studio 6.0 service packs, what, where, why

194295 How to tell that a Visual Studio service pack is installed

<div class="moreinformation_section">

Steps to Reproduce Behavior
<ol> Create a regular MFC DLL project using the App Wizard.</li> Create a new dialog box resource with one edit control, and OK and CANCEL buttons.</li> Create a class for the dialog box derived from CDialog. Name this class CMyDialog.</li>  Add the following function in mydialog.cpp: extern "C" void __declspec(dllexport) TestFunction;

void TestFunction {  AFX_MANAGE_STATE(AfxGetStaticModuleState); CMyDialog dlg; dlg.DoModal; }                   </li> Build the DLL.</li> Create a default App Wizard application EXE project.</li>  Replace the OnAppAbout function with the following: extern "C" void __declspec(dllimport) TestFunction;

void CMyTestApp::OnAppAbout {  TestFunction; }                   </li> Add the export library created in step 5 to the project created in step 6.</li> Copy the DLL built in step 5 to the debug folder for the application built in step 6.</li> Build and run.</li> On the Help menu, click About.</li></ol>

RESULTS: ASSERTS in wincore.cpp, lines 883 and 884 are triggered.

<div class="references_section">