Using ATL to Automate an MFC Application

  1. Lets start first to make the application visible. Add a property ‘Visible’ as a VARIANT_BOOL.
    The code should look like this:


    //———————————————–
    // get & put_Visible
    //———————————————–
    //
    STDMETHODIMP
    CAutoATLApp::get_Visible(VARIANT_BOOL *pVal)
    {
    METHOD_PROLOGUE_ATL

    CWnd* pMainWnd = AfxGetMainWnd();
    ASSERT(pMainWnd);
    *pVal = pMainWnd->IsWindowVisible();

    return S_OK;
    }

    STDMETHODIMP
    CAutoATLApp::put_Visible(VARIANT_BOOL newVal)
    {
    METHOD_PROLOGUE_ATL

    CWnd* pMainWnd = AfxGetMainWnd();
    ASSERT(pMainWnd);
    pMainWnd->ShowWindow(SW_SHOW);
    pMainWnd->UpdateWindow();

    return S_OK;
    }

  2. When i document i created by a client no frame or views are created. To be able to do so we must override CreateNewDocument in CMultiDocTemplate. CreateNewDocument is called from OpenDocumentFile to create a new document. But the document already exists. CrateNewDocument should therefor be altered NOT to create a document.
    Create a new class that inherites from CMultiDocTemplate and override CreateNewDocument and add a member variable CDocument* m_pDocument. CreateNewDocument should look like this:


    CDocument*
    CAnotherMultiDocTemplate::CreateNewDocument()
    {
    // default implementation constructs one from CRuntimeClass
    if (m_pDocClass == NULL)
    {
    TRACE0(“Error: you must override ”
    “CDocTemplate::CreateNewDocument.n”);
    ASSERT(FALSE);
    return NULL;
    }

    //———————————————–
    // BdL; Document has already been created!
    //
    // CDocument* pDocument =
    // (CDocument*)m_pDocClass->CreateObject();
    //———————————————–
    if (m_pDocument == NULL)
    {
    TRACE1(“Warning: Dynamic create of document ”
    “type %hs failed.n”,
    m_pDocClass->m_lpszClassName);
    return NULL;
    }

    ASSERT_KINDOF(CDocument, m_pDocument);
    AddDocument(m_pDocument);
    return m_pDocument;
    }

    To make your life a bit more easy, add the header file
    (AnotherMultiDocTemplate.h) of the new class to stdafx.h

  3. Alter in InitInstance of the application the DocumentTemplate:

    // CMultiDocTemplate* pDocTemplate;
    // pDocTemplate = new CMultiDocTemplate(
    to
    CAnotherMultiDocTemplate* pDocTemplate;
    pDocTemplate = new CAnotherMultiDocTemplate(
  4. Add FinalConstruct and FinalRelease to CAutoATLDoc. FinalConstruct will continue to create Frame and View. FinalRelease will the necessary cleanup.

    Add the following lines to CAutoAtlDoc.h


    HRESULT FinalConstruct();
    void FinalRelease();

    Add the following lines to CAutoAtlDoc.cpp


    HRESULT
    CAutoATLDoc::FinalConstruct()
    {
    METHOD_PROLOGUE_ATL

    CAutoATLApp* pApp = (CAutoATLApp*)AfxGetApp();
    ASSERT_VALID(pApp);

    // Find document template
    POSITION pos = pApp->GetFirstDocTemplatePosition();
    CAnotherMultiDocTemplate* pDocClass =
    (CAnotherMultiDocTemplate*)pApp->GetNextDocTemplate(pos);

    ASSERT_VALID(pDocClass);

    // Create view and frame
    pDocClass->m_pDocument = this;
    pDocClass->OpenDocumentFile(NULL, true);

    return S_OK;
    }

    void
    CAutoATLDoc::FinalRelease()
    {
    // Do will still have a View connected?
    // (The frame will no longer exist if the document
    // has been closed manually, because the OnClose
    // message is passed BEFORE deleting the document)
    POSITION pos = GetFirstViewPosition();
    if (pos != NULL) {
    // Prevent the document from deleting itself already.
    m_bAutoDelete = false;
    OnCloseDocument();
    m_bAutoDelete = true;
    }
    }

  5. In the application override OnFileOpen, OnFileNew and OpenDocumentFile. Normally OnFileOpen and OnFileNew create a document AND the frame and view. Now the frame and view are now created in the FinalConstruct of CAutoAtlDoc.

    //———————————————–
    //
    //———————————————–
    //
    void
    CAutoATLApp::OnFileNew()
    {
    // Dynamically create a new CFuchiaDocument.
    // The document will continue to create itself
    // in the constructor.
    IMPLEMENT_CREATE_DOCUMENT;
    }

    void
    CAutoATLApp::OnFileOpen()
    {
    // prompt the user (with all document templates)
    CString _lpszPathName;
    if (!DoPromptFileName(_lpszPathName,
    AFX_IDS_OPENFILE,
    OFN_HIDEREADONLY | OFN_FILEMUSTEXIST,
    TRUE, NULL))
    return; // open cancelled

    OpenDocumentFile(_lpszPathName);
    }

    CDocument*
    CAutoATLApp::OpenDocumentFile(LPCTSTR lpszFileName)
    {
    // Dynamically create a new CFuchiaDocument.
    // The document will continue to create itself
    // in the constructor.
    IMPLEMENT_CREATE_DOCUMENT;

    // Open an existing document
    CWaitCursor wait;
    if ( !pDoc->OnOpenDocument( lpszFileName ) )
    {
    // Unable to open the document.
    TRACE( “Unable to open the document
    in %s at %d.n”, THIS_FILE, __LINE__ );
    // We must delete the document instance.
    pDoc->Release();
    return NULL;
    }

    // Set the document file path and name.
    pDoc->SetPathName(lpszFileName);
    return pDoc;
    }

  6. IMPLEMENT_CREATE_DOCUMENT is a macro you can put on top in the document header file.

    //———————————————–
    // Call this MACRO when you need to create a new Document.
    // The document will construct itself further inside
    // FinalConstruct.
    #define IMPLEMENT_CREATE_DOCUMENT
    CComObject* pDoc;
    HRESULT hr = CComObject::CreateInstance(&pDoc);
    ASSERT(SUCCEEDED(hr));
    pDoc->InternalAddRef();
    //———————————————–

Downloads

Download demo project – 44 Kb

More by Author

Must Read