HOWTO: Automate Excel 97/2000 and Then Know the User Closed ItID: Q192348
|
This article illustrates how to:
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 Libraryand 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.
Q224925 INFO: Type Libraries for Office 2000 Have Changed
BOOL CAutoProjectApp::InitInstance()
{
if(!AfxOleInit()) // Your addition starts here.
{
AfxMessageBox("Could not initialize COM dll");
return FALSE;
} // End of your addition.
AfxEnableControlContainer();
.
.
.
}
#include <afxdisp.h>
#include "stdafx.h"
#include "excel8.h"
// for Excel 2000, use #include "excel9.h"
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);
}
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 TypelibOther articles about Automation are available on MSDN (Microsoft Developers Network). You can locate the specific MSDN Internet Web page that lists these at:
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
Last Reviewed: June 3, 1999