Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Automation of Form Views

0.00/5 (No votes)
2 May 2004 1  
An article on how to add automation to a form view

Introduction

If you've written applications, you know that you have to test them. Sometimes it would be nice if you could even write scripts to control your application. I like to use COM and Automation to accomplish both those things. Creating Document/View applications with scripting capabilities built in is really easy. Creating dialogs that support automation is really easy.

Unfortunately, the number of examples on how to exploit this feature are limited. Either the samples are rudimentary or too advanced. I try to explain how to create a simple Doc/view application that you can control through automation. In addition, I add some form controls in the view that you can also control.

Background

You can automate your dialogs and forms. However, you cannot create them without a host. This article will discuss a simple way to work around this without deviating from the document view architecture.

There are two ways around this:

  1. you can create a "factory" CCmdTarget based class that will allow you to "create" dialogs for export, or
  2. in a Document based app, you can use the Document as the "factory".

I'll explain the second option here, by going through the steps to create an "automated" form view.

Creating the Doc/View application with Automation enabled

Create a new VC++ MFC AppWizard Exe, I'll call it "MyMFCApp". click Next
  1. Make it an SDI app.
  2. Make sure Automation is checked.
  3. Change the base class from CView to CFormView
  4. Finish

Replacing the default FormView with an automated one

The formview that was added by default doesn't support automation, you either have to retrofit it, or create a form that does support automation and replace the default one. For this example, I'll just replace it.

  1. Add a new resource, Insert->Dialog->IDD_FORMVIEW
  2. Add a button to the form. and double click it
  3. choose "Create a new class"
  4. Give it a relatively unique name, I called mine CMyForm5486. Make sure the base class is CFormView derived, the default is CDialog. Make sure Automation radio button is set.
  5. Add a button handler for the newly added button and put in something like:
    void CMyForm5486::OnButton1()  
    { 
        ::AfxMessageBox( "My Button Press" ); 
    } 
    
  6. Now, replace the default form with our new one.
    1. Replace the header include in "MyMFCApp.cpp":
      //#include "MyMFCAppView.h" 
      
      #include "MyForm5486.h" 
      
      
    2. Open the CMyMFCAppApp::InitInstance and replace the code below:
          CSingleDocTemplate* pDocTemplate; 
          pDocTemplate = new CSingleDocTemplate( 
              IDR_MAINFRAME, 
              RUNTIME_CLASS(CMyMFCAppDoc), 
              RUNTIME_CLASS(CMainFrame),  
              RUNTIME_CLASS(CMyMFCAppView)); 
          AddDocTemplate(pDocTemplate); 
      
      with:
          CSingleDocTemplate* pDocTemplate; 
          pDocTemplate = new CSingleDocTemplate( 
              IDR_MAINFRAME, 
              RUNTIME_CLASS(CMyMFCAppDoc), 
              RUNTIME_CLASS(CMainFrame),  
              RUNTIME_CLASS(CMyForm5486)); 
          AddDocTemplate(pDocTemplate); 
      

Adding automation methods to the form.

Now, we add the automation code. This is the interface method that our clients will see.

  1. Right click on the IMyForm5846 interface, and choose Add Method. Call it ButtonClick with a return type of void.
  2. In ButtonClick, call the event handler, ie.
    void CMyForm5486::ButtonClick()  
    { 
        OnButton1(); 
    } 
    
Now, the COM method is the exact same thing as pressing the button.

Exposing the form from the Document

We now need a way to expose the form from the document.
  1. Right click on the IMyMFCApp interface, and choose Add Method. Call it GetFormView with a return type of LPDISPATCH. The sample code below will just return the first view position, You'll have to modify it to handle multiple forms if needed.
    LPDISPATCH CMyMFCAppDoc::GetFormView()  
    { 
        POSITION pos = this->GetFirstViewPosition(); 
      
        if (pos != NULL) 
        { 
            CView *pView = this->GetNextView(pos); 
     
            return pView->GetIDispatch( true ); 
        } 
     
        return NULL; 
    } 
    
  2. Run and test the app in standalone mode.

The automation test app

Now the automating test:
  1. Start VB and create a standalone Exe.
  2. Click Project->References. Select "Browse" and navigate to your Debug folder and select "MyMFCApp.tlb" and select Open, then OK.
  3. Press F2 and make sure you can see both your document and your formview classes and their methods.
  4. Open the form and add a button and a handler.
  5. Add the following code:
Private Sub Command1_Click() 
     
    ' Use CreateObject for DCOM 

    Dim doc As New MyMFCApp.Document 
    Dim frm As MyMFCApp.MyForm5487 
     
    If (doc Is Nothing) Then 
        MsgBox "failed to make document" 
    Else 
        Set frm = doc.GetFormView 
    End If 
     
    If (frm Is Nothing) Then 
        MsgBox "failed to get form" 
    Else 
        frm.ButtonClick 
    End If 
     
End Sub 

Running this "client" app will call the button handler though the automation interface.

Using the code

Note that you can only compile your interfaces (ODL files) while the TLB is unlocked. That is, if you have the TLB file open in VB, you won't be able to compile your ODL in VC++.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here