Q: How to get the active document anywhere in my application?
A: There are several methods, one is to get first the active frame then call CFrameWnd::GetActiveDocument.
In an SDI application the main frame is the main window itself so a function which gets the active document may look like:
In MDI applications, we have to additionally get the active MDI child frame.Code:CDocument* GetSDIActiveDocument() { CDocument* pDoc = NULL; CWnd* pWndMain = AfxGetMainWnd(); ASSERT(pWndMain); ASSERT(pWndMain->IsKindOf(RUNTIME_CLASS(CFrameWnd)) && !pWndMain->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))); // Not an SDI app. pDoc = ((CFrameWnd*)pWndMain)->GetActiveDocument(); return pDoc; }
Putting them together we can write the following generic function to be used either in SDI or MDI applications.Code:CDocument* GetMDIActiveDocument() { CDocument* pDoc = NULL; CWnd* pWndMain = AfxGetMainWnd(); ASSERT(pWndMain); ASSERT(pWndMain->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))); // Not an MDI app. CFrameWnd* pFrame = ((CMDIFrameWnd*)pWndMain)->MDIGetActive(); if(NULL != pFrame) { pDoc = pFrame->GetActiveDocument(); // get the active document } return pDoc; }
Before casting to a given document type we have to check if indeed the returned pointer is of that type.Code:CDocument* GenericGetActiveDocument() { CDocument* pDoc = NULL; CWnd* pWndMain = AfxGetMainWnd(); if(NULL != pWndMain) { if(pWndMain->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))) { // MDI application, so first we have to get the active MDI child frame. CFrameWnd* pFrame = ((CMDIFrameWnd*)pWndMain)->MDIGetActive(); if(NULL != pFrame) { pDoc = pFrame->GetActiveDocument(); } } else if(pWndMain->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { // SDI appllication so main window is the active frame. pDoc = ((CFrameWnd*)pWndMain)->GetActiveDocument(); } else { ASSERT(FALSE); // Neither MDI nor SDI application. } } return pDoc; }
To avoid such type of tests in many places, the GenericGetActiveDocument function can be improved, giving to it info about the required document type.Code:CDocument* pDoc = GenericGetActiveDocument(); if((NULL != pDoc) && pDoc->IsKindOf(RUNTIME_CLASS(CMyDocument))) { CMyDocument* pMyDoc = (CMyDocument*)pDoc; // enjoy of ponter to CMyDocument object. }
With the help of a little macro...Code:CDocument* GenericGetActiveDocument(CRuntimeClass* pClass) { ASSERT(NULL != pClass); // must be not NULL and derived from CDocument. ASSERT(pClass->IsDerivedFrom(RUNTIME_CLASS(CDocument))); CDocument* pDoc = NULL; CWnd* pWndMain = AfxGetMainWnd(); if(NULL != pWndMain) { if(pWndMain->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))) { // MDI application, so first we have to get the active MDI child frame. CFrameWnd* pFrame = ((CMDIFrameWnd*)pWndMain)->MDIGetActive(); if(NULL != pFrame) { CDocument* pActiveDoc = pFrame->GetActiveDocument(); if((NULL != pActiveDoc) && pActiveDoc->IsKindOf(pClass)) { // The found document is of required type pDoc = pActiveDoc; } } } else if(pWndMain->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { // SDI appllication so main window is the active frame. pDoc = ((CFrameWnd*)pWndMain)->GetActiveDocument(); } else { ASSERT(FALSE); // Neither MDI nor SDI application. } } return pDoc; }
...all remained to write anywhere in the SDI/MDI MFC application isCode:#define GET_ACTIVE_DOC(x) (x*)GenericGetActiveDocument(RUNTIME_CLASS(x))
Code:CMyDocument* pDoc = GET_ACTIVE_DOC(CMyDocument);
See also:


Reply With Quote
