DOCUMENT:Q230377 03-MAY-2001 [visualc] TITLE :BUG: Find/Replace ASSERT in MDI App w/ CRichEditView-based Views PRODUCT :Microsoft C Compiler PROD/VER:winnt:5.0,6.0 OPER/SYS: KEYWORDS:kbCmnDlg kbCmnDlgFind kbCmnDlgRepl kbMFC kbRichEdit kbDSupport kbGrpDSMFCATL ====================================================================== ------------------------------------------------------------------------------- The information in this article applies to: - The Microsoft Foundation Classes (MFC), used with: - Microsoft Visual C++, 32-bit Enterprise Edition, version 5.0 - Microsoft Visual C++, 32-bit Professional Edition, version 5.0 - Microsoft Visual C++, 32-bit Enterprise Edition, version 6.0 - Microsoft Visual C++, 32-bit Professional Edition, version 6.0 - Microsoft Visual C++, 32-bit Learning Edition, version 6.0 ------------------------------------------------------------------------------- SYMPTOMS ======== When you use a Find/Replace dialog box in a multiple document interface (MDI) application with CRichEditView-based views, you may receive one of the following messages: Debug Assertion Failed! Program: [Your.exe]. File: viewrich.cpp. Line: 1674. User breakpoint called from code at [SomeAddress]. (CRichEditView::AssertValid() will be on the stack) CAUSE ===== Dialog box ownership is established statically when the dialog box is created. The view that handles the initial ID_EDIT_FIND or ID_EDIT_REPLACE command becomes the owner of the dialog box. The owner is the window that receives FINDMSGSTRING notifications. When a Find/Replace dialog box survives its owner, all subsequent notifications are directed to a nonexistent window. The application is not aware that the dialog has been dismissed, which results in the assertions. RESOLUTION ========== WARNING: This resolution uses undocumented implementation features of the Microsoft Foundation Classes (MFC). Future versions of MFC may break programs that use this resolution. To resolve this problem, you need to do two things: - Override the OnActivateView method to update the dialog box owner dynamically whenever a CRichEditView view becomes active. - Provide a WM_DESTROY handler to dismiss the dialog box. See the sample code in the "More Information" section below for details. STATUS ====== Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article. MORE INFORMATION ================ Steps to Reproduce Behavior --------------------------- To reproduce this problem, perform the following steps: 1. In Visual C++, use AppWizard to create a default MDI application. In the last AppWizard step, specify CRichEditView as the base class for the view. 2. Compile and run the application. 3. Open a Find/Replace dialog box, close the child frame that contains the dialog box's owner, close the dialog box, and then create a new child frame. You should receive an assertion. -or- Open a Find/Replace dialog box, close the child frame that contains the dialog box's owner, create a new child frame, and then close the dialog box. You should receive an assertion. -or- Open a Find/Replace dialog box, close the child frame that contains the dialog box's owner, create a new child frame, and then attempt to execute a search in the new frame. No search is executed. Steps to Resolve the Problem ---------------------------- The following sample code illustrates how to override the OnActivateView method for CRichEditView-derived classes, and replace the WM_DESTROY handler: #include <..\Src\AfxImpl.h> void CRefindView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView) { // Set owner of Find/Replace dialog box. _AFX_RICHEDIT_STATE* pEditState = _afxRichEditState; if (pEditState && pEditState->pFindReplaceDlg && (pActivateView == this)) pEditState->pFindReplaceDlg->m_fr.hwndOwner = m_hWnd; CRichEditView::OnActivateView(bActivate, pActivateView, pDeactiveView); } void CRefindView::OnDestroy() { // Deactivate the item on destruction; // this is important when a splitter view is used. // CRichEditView::OnDestroy(); COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this); if (pActiveItem != NULL && pActiveItem->GetActiveView() == this) { pActiveItem->Deactivate(); ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL); } // Close Find/Replace dialog box if this is the last CRichEditView. _AFX_RICHEDIT_STATE* pEditState = _afxRichEditState; if (pEditState && pEditState->pFindReplaceDlg) { CWinApp* pApp = AfxGetApp(); // If there is no doc manager, there are no templates. if (pApp->m_pDocManager != NULL) { // Walk all templates. CDocTemplate* pTemplate; POSITION pos = pApp->m_pDocManager->GetFirstDocTemplatePosition(); while (pos != NULL) { pTemplate = pApp->m_pDocManager->GetNextDocTemplate(pos); ASSERT(pTemplate); // Walk all documents in the template. POSITION pos2 = pTemplate->GetFirstDocPosition(); while (pos2) { CDocument* pDoc = pTemplate->GetNextDoc(pos2); ASSERT(pDoc); // Walk all views in the document. POSITION pos3 = pDoc->GetFirstViewPosition(); while (pos3 != NULL) { CView* pView = pDoc->GetNextView(pos3); ASSERT(pView); // If we find another CRichEditView, // skip the code that closes the Find/Replace dialog box. if (pView->IsKindOf(RUNTIME_CLASS(CRichEditView)) && pView != this && ::IsWindow(pView->GetSafeHwnd())) { pEditState->pFindReplaceDlg->m_fr.hwndOwner = pView->m_hWnd; goto FoundRichEditView; } } } } } if (::IsWindow(pEditState->pFindReplaceDlg->m_hWnd)) pEditState->pFindReplaceDlg->SendMessage(WM_CLOSE); pEditState->pFindReplaceDlg = NULL; } FoundRichEditView: CRichEditView::OnDestroy(); } Additional query words: CRichEditView AssertValid Find Replace Assert ====================================================================== Keywords : kbCmnDlg kbCmnDlgFind kbCmnDlgRepl kbMFC kbRichEdit kbDSupport kbGrpDSMFCATL Technology : kbAudDeveloper kbMFC Version : winnt:5.0,6.0 Issue type : kbbug Solution Type : kbpending ============================================================================= THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY. Copyright Microsoft Corporation 2001.