📄 oleaut.cpp
字号:
//
// Class for creating OLE automation controllers.
//
// CreateObject() creates an automation object
// Invoke() will call a property or method of the automation object.
// GetProperty() returns a property
// SetProperty() changes a property
// Method() invokes a method
//
// For example, the following VB code will control Microsoft Word:
//
// Private Sub Form_Load()
// Dim wb As Object
// Set wb = CreateObject("Word.Basic")
// wb.AppShow
// wb.FileNewDefault
// wb.Insert "This is a test"
// wb.FileSaveAs "c:\sample.doc)"
// End Sub
//
// A C++ automation controller that does the same can be written as follows:
// the helper functions:
//
// Void FormLoad ()
// {
// COleAutomationControl Aut;
// Aut.CreateObject("Word.Basic");
// Aut.Method ("AppShow");
// Aut.Method ("FileNewDefault");
// Aut.Method ("Insert", "s", (LPOLESTR) OLESTR ("This is a test"));
// Aut.Method ("FileSaveAs", "s", OLESTR ("c:\\sample.doc"));
// }
//
//
#include "stdafx.h"
#include <stdarg.h>
#include "oleaut.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static bool CountArgsInFormat (LPCTSTR Format, UINT* nArgs);
static LPCTSTR GetNextVarType (LPCTSTR Format, VARTYPE* pVarType);
COleAutomationControl::COleAutomationControl ()
{
m_pDispatch = NULL;
m_hResult = NOERROR;
m_nErrArg = 0;
VariantInit (&m_VariantResult);
}
COleAutomationControl::~COleAutomationControl ()
{
DeleteObject ();
}
void COleAutomationControl::DeleteObject ()
{
if (m_pDispatch)
{
m_pDispatch->Release ();
m_pDispatch = NULL;
}
}
// Creates an instance of the Automation object and
// obtains it's IDispatch interface.
//
// Parameters:
// ProgId ProgID of Automation object
//
bool COleAutomationControl::CreateObject (char* ProgId)
{
CLSID ClsId; // CLSID of automation object
LPUNKNOWN pUnknown = NULL; // IUnknown of automation object
// Retrieve CLSID from the progID that the user specified
LPOLESTR OleProgId = TO_OLE_STR (ProgId);
m_hResult = CLSIDFromProgID (OleProgId, &ClsId);
if (FAILED (m_hResult))
goto error;
// Create an instance of the automation object and ask for the
// IDispatch interface
m_hResult = CoCreateInstance (ClsId, NULL, CLSCTX_SERVER,
IID_IUnknown, (void**) &pUnknown);
if (FAILED (m_hResult))
goto error;
m_hResult = pUnknown->QueryInterface (IID_IDispatch, (void**) &m_pDispatch);
if (FAILED (m_hResult))
goto error;
pUnknown->Release ();
return true;
error:
if (pUnknown)
pUnknown->Release ();
if (m_pDispatch)
m_pDispatch->Release ();
return false;
}
// Return the dispatch id of a named service
// This id can be used in subsequent calls to GetProperty (), SetProperty () and
// Method (). This is the prefered method when performance is important.
//
DISPID COleAutomationControl::GetDispatchId (char* Name)
{
DISPID DispatchId;
ASSERT (m_pDispatch);
// Get DISPID of property/method
LPOLESTR OleName = TO_OLE_STR (Name);
m_hResult = m_pDispatch->GetIDsOfNames (IID_NULL, &OleName, 1,
LOCALE_USER_DEFAULT, &DispatchId);
if (FAILED (m_hResult))
return NULL;
return DispatchId;
}
// The following functions use these parameters:
//
// Parameters:
//
// Name Name of property or method.
//
// Format Format string that describes the variable list of parameters that
// follows. The format string can contain the follwoing characters.
// & = mark the following format character as VT_BYREF
// B = VT_BOOL
// i = VT_I2
// I = VT_I4
// r = VT_R2
// R = VT_R4
// c = VT_CY
// s = VT_BSTR (string pointer can be passed,
// BSTR will be allocated by this function).
// e = VT_ERROR
// d = VT_DATE
// v = VT_VARIANT. Use this to pass data types that are not described
// in the format string. (For example SafeArrays).
// D = VT_DISPATCH
// U = VT_UNKNOWN
//
// ... Arguments of the property or method.
// Arguments are described by Format.
//
bool COleAutomationControl::GetProperty (char* Name)
{
return Invoke (DISPATCH_PROPERTYGET, Name, NULL, NULL);
}
bool COleAutomationControl::GetProperty (DISPID DispatchId)
{
return Invoke (DISPATCH_PROPERTYGET, DispatchId, NULL, NULL);
}
bool COleAutomationControl::PutProperty (char* Name, LPCTSTR Format, ...)
{
va_list ArgList;
va_start (ArgList, Format);
bool bRet = Invoke (DISPATCH_PROPERTYPUT, Name, Format, ArgList);
va_end (ArgList);
return bRet;
}
bool COleAutomationControl::PutProperty (DISPID DispatchId, LPCTSTR Format, ...)
{
va_list ArgList;
va_start (ArgList, Format);
bool bRet = Invoke (DISPATCH_PROPERTYPUT, DispatchId, Format, ArgList);
va_end (ArgList);
return bRet;
}
bool COleAutomationControl::Method (char* Name, LPCTSTR Format, ...)
{
va_list ArgList;
va_start (ArgList, Format);
bool bRet = Invoke (DISPATCH_METHOD, Name, Format, ArgList);
va_end (ArgList);
return bRet;
}
bool COleAutomationControl::Method (DISPID DispatchId, LPCTSTR Format, ...)
{
va_list ArgList;
va_start (ArgList, Format);
bool bRet = Invoke (DISPATCH_METHOD, DispatchId, Format, ArgList);
va_end (ArgList);
return bRet;
}
bool COleAutomationControl::Invoke (WORD Flags, char* Name,
LPCTSTR Format, va_list ArgList)
{
DISPID DispatchId = GetDispatchId (Name);
if (! DispatchId)
return false;
return Invoke (Flags, DispatchId, Format, ArgList);
}
bool COleAutomationControl::Invoke (WORD Flags, DISPID DispatchId,
LPCTSTR Format, va_list ArgList)
{
UINT ArgCount = 0;
VARIANTARG* ArgVector = NULL;
ASSERT (m_pDispatch);
DISPPARAMS DispatchParams;
memset (&DispatchParams, 0, sizeof (DispatchParams));
// Determine number of arguments
if (Format)
CountArgsInFormat (Format, &ArgCount);
// Property puts have a named argument that represents the value that
// the property is being assigned.
DISPID DispIdNamed = DISPID_PROPERTYPUT;
if (Flags & DISPATCH_PROPERTYPUT)
{
if (ArgCount == 0)
{
m_hResult = ResultFromScode (E_INVALIDARG);
return false;
}
DispatchParams.cNamedArgs = 1;
DispatchParams.rgdispidNamedArgs = &DispIdNamed;
}
if (ArgCount)
{
// Allocate memory for all VARIANTARG parameters
ArgVector = (VARIANTARG*) CoTaskMemAlloc (
ArgCount * sizeof (VARIANTARG));
if (! ArgVector)
{
m_hResult = ResultFromScode (E_OUTOFMEMORY);
return false;
}
memset (ArgVector, 0, sizeof (VARIANTARG) * ArgCount);
// Get ready to walk vararg list
LPCTSTR s = Format;
VARIANTARG *p = ArgVector + ArgCount - 1; // Params go in opposite order
for (;;)
{
VariantInit (p);
if (! (s = GetNextVarType (s, &p->vt)))
break;
if (p < ArgVector)
{
m_hResult = ResultFromScode (E_INVALIDARG);
goto Cleanup;
}
switch (p->vt)
{
case VT_I2:
V_I2 (p) = va_arg (ArgList, short);
break;
case VT_I4:
V_I4 (p) = va_arg (ArgList, long);
break;
case VT_R4:
V_R4 (p) = va_arg (ArgList, float);
break;
case VT_DATE:
case VT_R8:
V_R8 (p) = va_arg (ArgList, double);
break;
case VT_CY:
V_CY (p) = va_arg (ArgList, CY);
break;
case VT_BSTR:
V_BSTR (p) = SysAllocString (va_arg (ArgList,
OLECHAR*));
if (! p->bstrVal)
{
m_hResult = ResultFromScode (E_OUTOFMEMORY);
p->vt = VT_EMPTY;
goto Cleanup;
}
break;
case VT_DISPATCH:
V_DISPATCH (p) = va_arg (ArgList, LPDISPATCH);
break;
case VT_ERROR:
V_ERROR (p) = va_arg (ArgList, SCODE);
break;
case VT_BOOL:
V_BOOL (p) = va_arg (ArgList, BOOL) ? -1 : 0;
break;
case VT_VARIANT:
*p = va_arg (ArgList, VARIANTARG);
break;
case VT_UNKNOWN:
V_UNKNOWN (p) = va_arg (ArgList, LPUNKNOWN);
break;
case VT_I2 | VT_BYREF:
V_I2REF (p) = va_arg (ArgList, short*);
break;
case VT_I4 | VT_BYREF:
V_I4REF (p) = va_arg (ArgList, long*);
break;
case VT_R4 | VT_BYREF:
V_R4REF (p) = va_arg (ArgList, float*);
break;
case VT_R8 | VT_BYREF:
V_R8REF (p) = va_arg (ArgList, double*);
break;
case VT_DATE | VT_BYREF:
V_DATEREF (p) = va_arg (ArgList, DATE*);
break;
case VT_CY | VT_BYREF:
V_CYREF (p) = va_arg (ArgList, CY*);
break;
case VT_BSTR | VT_BYREF:
V_BSTRREF (p) = va_arg (ArgList, BSTR*);
break;
case VT_DISPATCH | VT_BYREF:
V_DISPATCHREF (p) = va_arg (ArgList, LPDISPATCH*);
break;
case VT_ERROR | VT_BYREF:
V_ERRORREF (p) = va_arg (ArgList, SCODE*);
break;
case VT_BOOL | VT_BYREF:
{
BOOL* pBool = va_arg (ArgList, BOOL*);
*pBool = 0;
V_BOOLREF (p) = (VARIANT_BOOL*) pBool;
}
break;
case VT_VARIANT | VT_BYREF:
V_VARIANTREF (p) = va_arg (ArgList, VARIANTARG*);
break;
case VT_UNKNOWN | VT_BYREF:
V_UNKNOWNREF (p) = va_arg (ArgList, LPUNKNOWN*);
break;
default:
{
m_hResult = ResultFromScode (E_INVALIDARG);
goto Cleanup;
}
break;
}
--p; // Get ready to fill next argument
}
}
DispatchParams.cArgs = ArgCount;
DispatchParams.rgvarg = ArgVector;
// Initialize return variant, in case caller forgot. Caller can pass
// NULL if return value is not expected.
VariantInit (&m_VariantResult);
// Make the call
m_hResult = m_pDispatch->Invoke (DispatchId, IID_NULL, LOCALE_USER_DEFAULT,
Flags, &DispatchParams, &m_VariantResult,
&m_ExceptionInfo, &m_nErrArg);
Cleanup:
// Cleanup any arguments that need cleanup
if (ArgCount)
{
VARIANTARG* p = ArgVector;
while (ArgCount--)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -