HOWTO: Automate Excel 97/2000 and Then Know the User Closed It
ID: Q192348
|
The information in this article applies to:
-
Microsoft Visual Studio 97
-
Microsoft Visual C++, 32-bit Editions, versions 5.0, 6.0
-
Microsoft Office 2000 Developer
-
Microsoft Excel 2000
-
Microsoft Excel 97 for Windows
-
The Microsoft Foundation Classes (MFC)
SUMMARY
This article illustrates how to:
- Automate Microsoft Excel 97 or Excel 2000 using Microsoft Visual C++ and Microsoft
Foundation Classes (MFC).
- Wait for the end-user to close that instance of Excel.
- Have your VC++ controller know that Excel is closed.
MORE INFORMATION
Microsoft Excel 97 or Excel 2000 do not raise a "Quit" event that can observed by other
processes. When an out-of-process application that controls an instance of
Excel releases all object references to the instance and tells it to quit,
that controller knows Excel has terminated. But, when the controller
creates and makes an instance of Excel visible it does not know when the
end-user has closed Excel. As long as the controlling application has
unreleased object references to the instance, Excel remains loaded and
registered in the Running Object Table.
This article uses the concepts of Microsoft Knowledge Base article:
Q178749 HOWTO: Create Automation Project Using MFC and a Type Library
and modifies that article's step 14 to include sample code to illustrate
one method of determining that the end-user has actually closed the
instance of Excel. The approach is to call WaitForSingleObject() to
determine that the specific Excel process has terminated.
Notes for Automating Microsoft Excel 2000
Some methods and properties have changed for Microsoft Excel 2000. For additional
information about using the sample code described in this article with the Microsoft
Excel 2000 type library, please see the following article in the Microsoft Knowledge Base:
Q224925 INFO: Type Libraries for Office 2000 Have Changed
Create an Automation Project
- With Microsoft Developer Studio, start a new "MFC AppWizard (exe)"
project named AutoProject.
- In step 1 of the MFC AppWizard, choose Dialog Based for the application
type and click Finish.
The New Project Information dialog box appears and indicates that the
Classes to be created include:
Application: CAutoProjectApp in AutoProject.h and AutoProject.cpp
Dialog: CAutoProjectDlg in AutoProject.h and AutoProjectDlg.cpp
Click OK to create the project.
- In the project workspace, click the "Resource View" tab. Double-click
AutoProject Resources to expand the resource tree. Double-click Dialog
in the Resource tree and double-click to select the dialog box resource
IDD_AUTOPROJECT_DIALOG.
- Remove the Label control (IDC_STATIC).
- Change the name of the OK button to IDSEEXLQUIT and the caption to
"See Excel Quit." Close the AutoProject.rc dialog box design form.
- Click ClassWizard on the View menu (or press CTRL+W).
- Select the Message Maps tab. Select IDSEEXLQUIT in the Object Ids list
box and select BN_CLICKED in the Messages list box. Click Add Function
and accept the function name OnSeexlquit. Click OK to close the
ClassWizard.
NOTE: This step adds a declaration for the function member
OnSeexlquit(); to the header file named AutoProjectDLG.h. This step also
adds an empty skeleton message handler function named
CAutoProjectDlg::OnSeexlquit() to the file named AutoProjectDLG.cpp.
- Click ClassWizard on the View menu (or press CTRL+W).
- Select the Automation tab. Click Add Class and choose "From a type
library." Navigate to select the object library for Microsoft Excel 8.0
Object Library; (the default location is C:\Program Files\Microsoft
Office\Office\Excel8.olb) and click Open. Select all classes in the
Confirm Classes list and click OK. For Excel 2000, select the object
library for Microsoft Excel 9.0 Object Library; The default location
is C:\Program Files\Microsoft Office\Office\Excel9.ol.
NOTE: The list box in the Confirm Classes dialog box contains all of
the IDispatch interfaces in the Microsoft Excel type library. In the
lower half of the dialog box you will see that an Implementation file
named Excel8.cpp contains generated class wrappers derived from
ColeDispatchDriver(), and the appropriate declaration header file is
named Excel8.h. For Excel 2000, the implementation file is Excel9.cpp
and the declaration header file is Excel9.h.
- Click OK to close the MFC ClassWizard dialog box.
- Add the following code to the CAutoProjectApp::InitInstance() function,
which loads and enables the COM services library:
BOOL CAutoProjectApp::InitInstance()
{
if(!AfxOleInit()) // Your addition starts here.
{
AfxMessageBox("Could not initialize COM dll");
return FALSE;
} // End of your addition.
AfxEnableControlContainer();
.
.
.
}
- Add the following line to the #include statements at the top of the
AutoProject.cpp program file:
#include <afxdisp.h>
- Add the include statement for Excel8.h after the include statement for
Stdafx.h at the top of the AutoProjectDlg.cpp program file:
#include "stdafx.h"
#include "excel8.h"
// for Excel 2000, use #include "excel9.h"
- Add automation code to the CAutoProjectDlg::OnSeexlquit() so that it
appears as shown below:
void CAutoProjectDlg::OnSeexlquit() // Message handler function.
{
char buf[1024]; // General purpose message buffer.
_Application oExcel; // oExcel is an _Application object.
Workbooks oBooks;
LPDISPATCH lpDisp;
// Common OLE-variants... Easy variants to use for calling arguments.
COleVariant
covTrue((short)TRUE),
covFalse((short)FALSE),
covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
// Start Excel and get Application object.
if(!oExcel.CreateDispatch("Excel.Application"))
{
AfxMessageBox("Couldn't CreateDispatch on Excel");
return;
}
// Set visible.
oExcel.SetVisible(TRUE);
oExcel.SetUserControl(TRUE); // This is a property of the
// _Application object. Set it so you
// can Release the oExcel and
// oBooks objects without killing
// Excel.
// Get Workbooks collection...
lpDisp = oExcel.GetWorkbooks(); // Get an IDispatch pointer
ASSERT(lpDisp); // or fail.
oBooks.AttachDispatch( lpDisp ); // Attach IDispatch pointer to
// oBooks object.
// Open a workbook...
lpDisp = oBooks.Open("C:\\Mybook.xls", // Change for your .xls.
covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional, covOptional, covOptional
);
ASSERT(lpDisp); // It better have worked?
HWND hWnd;
hWnd = ::FindWindow("XLMain", // Pointer to class name.
NULL // Pointer to window name option.
);
if(NULL==hWnd)
{
long lErr = GetLastError();
sprintf(buf, "FindWindow error code = %d", lErr);
AfxMessageBox(buf);
}
DWORD pid; // Variable to hold the process ID.
DWORD dThread; // Variable to hold (unused) thread ID.
dThread = GetWindowThreadProcessId(hWnd, // Handle to window.
&pid // Address of variable
// for process identifier.
);
HANDLE hProcess; // Handle to existing process
hProcess = OpenProcess(SYNCHRONIZE | PROCESS_ALL_ACCESS, // access
// flag
TRUE, // handle inheritance flag
pid // process identifier
);
oBooks.ReleaseDispatch(); // Release the object-IDispatch binding.
oExcel.ReleaseDispatch();
oBooks = NULL; // Destroy the object references.
oExcel = NULL;
DWORD dwReason; // Variable to receive signal.
dwReason = WaitForSingleObject(hProcess, // Handle to object to
// wait for its end.
INFINITE // Time-out interval in
// milliseconds.
);
sprintf(buf, "Reason for Wait to terminate is %d", dwReason);
// Zero is good.
AfxMessageBox(buf);
}
- Build and run the project. When the dialog box appears, minimize
Visual Studio, leaving the dialog box from your project. Click the
"See Excel Quit" button. Wait for Excel to appear and be visible.
Once it is visible, at your leisure, click the control button at the
right end of the title bar (the "X") to close Excel.
REFERENCES
This article presents a specific approach to determining that the end-user
has terminated an instance of Excel. If you would like more information
about building a dialog-box project for other Automation servers, please
see the following article in the Microsoft Knowledge Base.
Q178749 HOWTO: Create an Automation Project Using MFC and a Typelib
Other articles about Automation are available on MSDN (Microsoft Developers
Network). You can locate the specific MSDN Internet Web page that lists
these at:
http://support.microsoft.com/support/visualc/atlmfc/oleatmfc.asp.
For more information on catching application events, please see the
following articles in the Microsoft Knowledge Base:
Q183599 HOWTO: Catch Microsoft Word 97 Events Using Visual C++
Q172055 HOWTO: Use Events to Determine When Word Quits
(NOTE: This example uses Microsoft Visual Basic.)
Additional query words:
IDispatch
Keywords : kbole kbAutomation kbMFC kbVC500 kbVC600 kbVS97 kbOffice2000 kbExcel97 kbexcel2000
Version : WINDOWS:2000,97; winnt:5.0,6.0; :
Platform : WINDOWS winnt
Issue type : kbhowto
|