HOWTO: Do 16-Bit Automation in C++ Using VC 1.52ID: Q194656
|
This article shows you how to build a 16-bit Automation client written in VC++ 1.52 to automate Microsoft Excel 97 and Microsoft Word 97, without using MFC.
Although it is recommended that you port your code to 32-bit, some
implementations require 16-bit code for compatibility and integration with
other 16-bit applications. Please remember that if your code is going to
run on Windows 95, you must install DCOM. Without DCOM installed, 16-bit
automation clients on Windows 95 usually crash. This is also true for 32-
bit code that is called via a thunk from 16-bit.
Follow the steps below to create the example:
#include <windows.h>
#include <ole2.h> // Core OLE support
#include <dispatch.h> // IDispatch/Automation support
#include <olenls.h> // National Language support for LOCALE constants
#include <stdio.h>
#include <stdarg.h> // For variable-argument use in AutoWrap16()
#include <stdlib.h> // For _exit() in AutoWrap16()...
// Helpful functions...
char buf[8192];
void ShowMsg(char *str) {
MessageBox(NULL, str, "Hey", MB_OK);
}
void ShowErr(char *str, HRESULT hr) {
wsprintf(buf, "%s: %ld (%08lx)", str, hr, hr);
MessageBox(NULL, buf, "Error", MB_OK);
}
void PumpMessages(void) {
MSG msg;
while(PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Wrapper function for making generic 16-bit Automation calls...
HRESULT AutoWrap16(int autoType, VARIANT *pvResult,
IDispatch *pDisp, char *ptName, int cArgs...) {
// Begin variable-argument list...
va_list marker;
va_start(marker, cArgs);
if(!pDisp) {
MessageBox(NULL, "NULL IDispatch passed to AutoWrap()",
"Error", 0x10010);
_exit(0);
}
// Variables used...
DISPPARAMS dp = { NULL, NULL, 0, 0 };
DISPID dispidNamed = DISPID_PROPERTYPUT;
DISPID dispID;
HRESULT hr;
char buf[200];
// Get DISPID for name passed...
hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1,
LOCALE_USER_DEFAULT, &dispID);
if(FAILED(hr)) {
wsprintf(buf, "IDispatch::GetIDsOfNames(\"%s\") failed w/err"
" 0x%08lx", ptName, hr);
MessageBox(NULL, buf, "AutoWrap()", 0x10010);
_exit(0);
return hr;
}
// Allocate memory for arguments...
VARIANT *pArgs = new VARIANT[cArgs+1];
// Extract arguments...
for(int i=0; i<cArgs; i++) {
pArgs[i] = va_arg(marker, VARIANT);
}
// Build DISPPARAMS
dp.cArgs = cArgs;
dp.rgvarg = pArgs;
// Handle special-case for property-puts!
if(autoType & DISPATCH_PROPERTYPUT) {
dp.cNamedArgs = 1;
dp.rgdispidNamedArgs = &dispidNamed;
}
// Make the call!
hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
autoType, &dp, pvResult, NULL, NULL);
if(FAILED(hr)) {
wsprintf(buf, "IDispatch::Invoke(\"%s\"=%08lx) failed w/err"
" 0x%08lx", ptName, dispID, hr);
MessageBox(NULL, buf, "AutoWrap()", 0x10010);
_exit(0);
return hr;
}
// End variable-argument section...
va_end(marker);
delete [] pArgs;
return hr;
}
void ExcelTest(void) {
// Get CLSID for our server...
CLSID clsid;
HRESULT hr = CLSIDFromProgID("Excel.Application", &clsid);
if(FAILED(hr)) {
ShowErr("CLSIDFromProgID() failed", hr);
return;
}
// Start the server...
IUnknown *pUnk = NULL;
hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER,
IID_IUnknown, (void **)&pUnk);
if(FAILED(hr)) {
ShowErr("CoCreateInstance() failed", hr);
return;
}
// Query for IDispatch
IDispatch *pDispRoot = NULL;
hr = pUnk->QueryInterface(IID_IDispatch, (void **)&pDispRoot);
if(FAILED(hr)) {
ShowErr("QueryInterface(IID_IDispatch) failed", hr);
pUnk->Release();
return;
}
// Get App IDispatch
IDispatch *pDispApp = NULL;
{
VARIANT result;
VariantInit(&result);
AutoWrap16(DISPATCH_PROPERTYGET, &result, pDispRoot,
"Application", 0);
pDispApp = result.pdispVal;
}
// Set Visible...
{
VARIANT parm;
parm.vt = VT_I4;
parm.lVal = 1;
AutoWrap16(DISPATCH_PROPERTYPUT, 0, pDispApp, "Visible", 1,
parm);
}
// Get Workbooks collection...
IDispatch *pDispBooks = NULL;
{
VARIANT result;
VariantInit(&result);
AutoWrap16(DISPATCH_PROPERTYGET, &result, pDispApp,
"Workbooks", 0);
pDispBooks = result.pdispVal;
}
// Call Workbooks::Add()...
IDispatch *pDispBook = NULL;
{
VARIANT result;
VariantInit(&result);
AutoWrap16(DISPATCH_METHOD|DISPATCH_PROPERTYGET, &result,
pDispBooks, "Add", 0);
pDispBook = result.pdispVal;
}
// Get ActiveSheet...
IDispatch *pDispSheet = NULL;
{
VARIANT result;
VariantInit(&result);
AutoWrap16(DISPATCH_PROPERTYGET, &result, pDispBook,
"ActiveSheet", 0);
pDispSheet = result.pdispVal;
}
// Set a range of values...
for(int i=1; i<10; i++) {
for(int j=1; j<10; j++) {
// Get Range object (i,j)...
IDispatch *pDispRange = NULL;
{
VARIANT result;
VariantInit(&result);
VARIANT p1, p2;
p1.vt = p2.vt = VT_I4;
p1.lVal = i;
p2.lVal = j;
AutoWrap16(DISPATCH_PROPERTYGET, &result, pDispSheet,
"Cells", 2, p2, p1);
pDispRange = result.pdispVal;
}
// Set Range.Value to i*j
{
VARIANT parm;
parm.vt = VT_I4;
parm.lVal = i*j;
AutoWrap16(DISPATCH_PROPERTYPUT, 0, pDispRange, "Value",
1, parm);
}
// Release Range...
pDispRange->Release();
}
}
//ShowMsg("Preparing to clean up...");
// Clean up...
pDispSheet->Release();
pDispBook->Release();
pDispBooks->Release();
pDispApp->Release();
pDispRoot->Release();
pUnk->Release();
}
void WordBasicTest(void) {
// Get CLSID for our server...
CLSID clsid;
HRESULT hr = CLSIDFromProgID("Word.Basic", &clsid);
if(FAILED(hr)) {
ShowErr("CLSIDFromProgID() failed", hr);
return;
}
// Start the server...
IUnknown *pUnk = NULL;
hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER,
IID_IUnknown, (void **)&pUnk);
if(FAILED(hr)) {
ShowErr("CoCreateInstance() failed", hr);
return;
}
// Query for IDispatch
IDispatch *pDispRoot = NULL;
hr = pUnk->QueryInterface(IID_IDispatch, (void **)&pDispRoot);
if(FAILED(hr)) {
ShowErr("QueryInterface(IID_IDispatch) failed", hr);
pUnk->Release();
return;
}
// Call AppShow
AutoWrap16(DISPATCH_METHOD, 0, pDispRoot, "AppShow", 0);
// Call FileNew
AutoWrap16(DISPATCH_METHOD, 0, pDispRoot, "FileNew", 0);
// Call Insert "Hello World"
{
VARIANT parm;
parm.vt = VT_BSTR;
parm.bstrVal = SysAllocString("Hello World!");
AutoWrap16(DISPATCH_METHOD, 0, pDispRoot, "Insert", 1, parm);
SysFreeString(parm.bstrVal);
}
// Clean up...
pDispRoot->Release();
pUnk->Release();
}
void WordApplicationTest(void) {
// Get CLSID for our server...
CLSID clsid;
HRESULT hr = CLSIDFromProgID("Word.Application", &clsid);
if(FAILED(hr)) {
ShowErr("CLSIDFromProgID() failed", hr);
return;
}
// Start the server...
IUnknown *pUnk = NULL;
hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER,
IID_IUnknown, (void **)&pUnk);
if(FAILED(hr)) {
ShowErr("CoCreateInstance() failed", hr);
return;
}
// Query for IDispatch
IDispatch *pDispRoot = NULL;
hr = pUnk->QueryInterface(IID_IDispatch, (void **)&pDispRoot);
if(FAILED(hr)) {
ShowErr("QueryInterface(IID_IDispatch) failed", hr);
pUnk->Release();
return;
}
// Get App IDispatch
IDispatch *pDispApp = NULL;
{
VARIANT result;
VariantInit(&result);
AutoWrap16(DISPATCH_PROPERTYGET, &result, pDispRoot,
"Application", 0);
pDispApp = result.pdispVal;
}
// Set Visible...
{
VARIANT parm;
parm.vt = VT_I4;
parm.lVal = 1;
AutoWrap16(DISPATCH_PROPERTYPUT, 0, pDispApp, "Visible", 1,
parm);
}
// Get Documents collection...
IDispatch *pDispDocs = NULL;
{
VARIANT result;
VariantInit(&result);
AutoWrap16(DISPATCH_PROPERTYGET, &result, pDispApp,
"Documents", 0);
pDispDocs = result.pdispVal;
}
// Call Documents::Add()...
IDispatch *pDispDoc = NULL;
{
VARIANT result;
VariantInit(&result);
AutoWrap16(DISPATCH_METHOD|DISPATCH_PROPERTYGET, &result,
pDispDocs, "Add", 0);
pDispDoc = result.pdispVal;
}
// Get Selection...
IDispatch *pDispSelection = NULL;
{
VARIANT result;
VariantInit(&result);
AutoWrap16(DISPATCH_PROPERTYGET, &result, pDispApp,
"Selection", 0);
pDispSelection = result.pdispVal;
}
// Call TypeText "Hello World"
{
VARIANT parm;
parm.vt = VT_BSTR;
parm.bstrVal = SysAllocString("Hello World!");
AutoWrap16(DISPATCH_METHOD, 0, pDispSelection, "TypeText", 1,
parm);
SysFreeString(parm.bstrVal);
}
//ShowMsg("Preparing to clean up...");
// Clean up...
pDispSelection->Release();
pDispDoc->Release();
pDispDocs->Release();
pDispApp->Release();
pDispRoot->Release();
pUnk->Release();
}
// Program entry-point...
void main(void) {
// Initialize OLE Libraries...
OleInitialize(NULL);
// Perform the tests...
ShowMsg("Click me to Automate Excel.Application...");
ExcelTest();
ShowMsg("Click me to Automate Word.Application...");
WordApplicationTest();
ShowMsg("Click me to Automate Word.Basic...");
WordBasicTest();
// Uninitialize OLE Libraries...
OleUninitialize();
ShowMsg("Exiting...");
}
© Microsoft Corporation 1998, All Rights Reserved.
Contributions by Joe Crump, Microsoft Corporation
Additional query words:
Keywords : kb16bitonly kbAutomation kbDCOM kbVC152 kbWinOS95 kbWinOS98
Version : WINDOWS:1.52
Platform : WINDOWS
Issue type : kbhowto
Last Reviewed: July 29, 1999