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:
- you can create a "factory"
CCmdTarget
based class that will allow you to "create" dialogs for export, or
- 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
- Make it an SDI app.
- Make sure Automation is checked.
- Change the base class from
CView
to CFormView
- 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.
- Add a new resource, Insert->Dialog->IDD_FORMVIEW
- Add a button to the form. and double click it
- choose "Create a new class"
- 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.
- Add a button handler for the newly added button and put in something like:
void CMyForm5486::OnButton1()
{
::AfxMessageBox( "My Button Press" );
}
- Now, replace the default form with our new one.
- Replace the header include in "MyMFCApp.cpp":
#include "MyForm5486.h"
- 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.
- Right click on the
IMyForm5846
interface, and choose Add Method. Call it ButtonClick
with a return type of void.
- 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.
- 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;
}
- Run and test the app in standalone mode.
The automation test app
Now the automating test:
- Start VB and create a standalone Exe.
- Click Project->References. Select "Browse" and navigate to your Debug folder and select "MyMFCApp.tlb" and select Open, then OK.
- Press F2 and make sure you can see both your document and your formview classes and their methods.
- Open the form and add a button and a handler.
- Add the following code:
Private Sub Command1_Click()
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++.