mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
532 lines
12 KiB
532 lines
12 KiB
// This is a part of the Microsoft Foundation Classes C++ library.
|
|
// Copyright (C) 1992-1995 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Microsoft Foundation Classes Reference and related
|
|
// electronic documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Microsoft Foundation Classes product.
|
|
|
|
#include "stdafx.h"
|
|
#include <stdarg.h>
|
|
|
|
#ifdef AFX_OLE5_SEG
|
|
#pragma code_seg(AFX_OLE5_SEG)
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COleDispatchDriver constructors/destructors
|
|
|
|
HRESULT AFXAPI AfxGetClassIDFromString(LPCTSTR lpsz, LPCLSID lpClsID)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
HRESULT hr;
|
|
if (lpsz[0] == '{')
|
|
hr = CLSIDFromString((LPOLESTR)T2COLE(lpsz), lpClsID);
|
|
else
|
|
hr = CLSIDFromProgID(T2COLE(lpsz), lpClsID);
|
|
return hr;
|
|
}
|
|
|
|
COleDispatchDriver::COleDispatchDriver()
|
|
{
|
|
m_lpDispatch = NULL;
|
|
m_bAutoRelease = TRUE;
|
|
}
|
|
|
|
COleDispatchDriver::COleDispatchDriver(LPDISPATCH lpDispatch, BOOL bAutoRelease)
|
|
{
|
|
m_lpDispatch = lpDispatch;
|
|
m_bAutoRelease = bAutoRelease;
|
|
}
|
|
|
|
COleDispatchDriver::COleDispatchDriver(const COleDispatchDriver& dispatchSrc)
|
|
{
|
|
ASSERT(this != &dispatchSrc); // constructing from self?
|
|
|
|
m_lpDispatch = dispatchSrc.m_lpDispatch;
|
|
if (m_lpDispatch != NULL)
|
|
m_lpDispatch->AddRef();
|
|
m_bAutoRelease = TRUE;
|
|
}
|
|
|
|
const COleDispatchDriver&
|
|
COleDispatchDriver::operator=(const COleDispatchDriver& dispatchSrc)
|
|
{
|
|
if (this != &dispatchSrc)
|
|
{
|
|
LPDISPATCH lpTemp = m_lpDispatch;
|
|
m_lpDispatch = dispatchSrc.m_lpDispatch;
|
|
if (m_lpDispatch != NULL)
|
|
m_lpDispatch->AddRef();
|
|
if (lpTemp != NULL && m_bAutoRelease)
|
|
lpTemp->Release();
|
|
m_bAutoRelease = TRUE;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
BOOL COleDispatchDriver::CreateDispatch(REFCLSID clsid, COleException* pError)
|
|
{
|
|
ASSERT(m_lpDispatch == NULL);
|
|
|
|
m_bAutoRelease = TRUE; // good default is to auto-release
|
|
|
|
// create an instance of the object
|
|
LPUNKNOWN lpUnknown = NULL;
|
|
SCODE sc = CoCreateInstance(clsid, NULL, CLSCTX_ALL | CLSCTX_REMOTE_SERVER,
|
|
IID_IUnknown, (LPLP)&lpUnknown);
|
|
if (sc == E_INVALIDARG)
|
|
{
|
|
// may not support CLSCTX_REMOTE_SERVER, so try without
|
|
sc = CoCreateInstance(clsid, NULL, CLSCTX_ALL & ~CLSCTX_REMOTE_SERVER,
|
|
IID_IUnknown, (LPLP)&lpUnknown);
|
|
}
|
|
if (FAILED(sc))
|
|
goto Failed;
|
|
|
|
// make sure it is running
|
|
sc = OleRun(lpUnknown);
|
|
if (FAILED(sc))
|
|
goto Failed;
|
|
|
|
// query for IDispatch interface
|
|
m_lpDispatch = QUERYINTERFACE(lpUnknown, IDispatch);
|
|
if (m_lpDispatch == NULL)
|
|
goto Failed;
|
|
|
|
lpUnknown->Release();
|
|
ASSERT(m_lpDispatch != NULL);
|
|
return TRUE;
|
|
|
|
Failed:
|
|
RELEASE(lpUnknown);
|
|
if (pError != NULL)
|
|
pError->m_sc = sc;
|
|
TRACE1("Warning: CreateDispatch returning scode = %s.\n",
|
|
AfxGetFullScodeString(sc));
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL COleDispatchDriver::CreateDispatch(LPCTSTR lpszProgID,
|
|
COleException* pError)
|
|
{
|
|
ASSERT(m_lpDispatch == NULL);
|
|
|
|
// map prog id to CLSID
|
|
CLSID clsid;
|
|
SCODE sc = AfxGetClassIDFromString(lpszProgID, &clsid);
|
|
if (FAILED(sc))
|
|
{
|
|
if (pError != NULL)
|
|
pError->m_sc = sc;
|
|
return FALSE;
|
|
}
|
|
|
|
// create with CLSID
|
|
return CreateDispatch(clsid, pError);
|
|
}
|
|
|
|
void COleDispatchDriver::AttachDispatch(LPDISPATCH lpDispatch,
|
|
BOOL bAutoRelease)
|
|
{
|
|
ASSERT(lpDispatch != NULL);
|
|
|
|
ReleaseDispatch(); // detach previous
|
|
m_lpDispatch = lpDispatch;
|
|
m_bAutoRelease = bAutoRelease;
|
|
}
|
|
|
|
void COleDispatchDriver::ReleaseDispatch()
|
|
{
|
|
if (m_lpDispatch != NULL)
|
|
{
|
|
if (m_bAutoRelease)
|
|
m_lpDispatch->Release();
|
|
m_lpDispatch = NULL;
|
|
}
|
|
}
|
|
|
|
LPDISPATCH COleDispatchDriver::DetachDispatch()
|
|
{
|
|
LPDISPATCH lpDispatch = m_lpDispatch;
|
|
m_lpDispatch = NULL; // detach without Release
|
|
return lpDispatch;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COleDispatchDriver implementation
|
|
|
|
#if defined(_68K_) || defined(_X86_)
|
|
#define DOUBLE_ARG _AFX_DOUBLE
|
|
#else
|
|
#define DOUBLE_ARG double
|
|
#endif
|
|
|
|
|
|
void COleDispatchDriver::InvokeHelperV(DISPID dwDispID, WORD wFlags,
|
|
VARTYPE vtRet, void* pvRet, const BYTE* pbParamInfo, va_list argList)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
if (m_lpDispatch == NULL)
|
|
{
|
|
TRACE0("Warning: attempt to call Invoke with NULL m_lpDispatch!\n");
|
|
return;
|
|
}
|
|
|
|
DISPPARAMS dispparams;
|
|
memset(&dispparams, 0, sizeof dispparams);
|
|
|
|
// determine number of arguments
|
|
if (pbParamInfo != NULL)
|
|
dispparams.cArgs = lstrlenA((LPCSTR)pbParamInfo);
|
|
|
|
DISPID dispidNamed = DISPID_PROPERTYPUT;
|
|
if (wFlags & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF))
|
|
{
|
|
ASSERT(dispparams.cArgs > 0);
|
|
dispparams.cNamedArgs = 1;
|
|
dispparams.rgdispidNamedArgs = &dispidNamed;
|
|
}
|
|
|
|
if (dispparams.cArgs != 0)
|
|
{
|
|
// allocate memory for all VARIANT parameters
|
|
VARIANT* pArg = new VARIANT[dispparams.cArgs];
|
|
ASSERT(pArg != NULL); // should have thrown exception
|
|
dispparams.rgvarg = pArg;
|
|
memset(pArg, 0, sizeof(VARIANT) * dispparams.cArgs);
|
|
|
|
// get ready to walk vararg list
|
|
const BYTE* pb = pbParamInfo;
|
|
pArg += dispparams.cArgs - 1; // params go in opposite order
|
|
|
|
while (*pb != 0)
|
|
{
|
|
ASSERT(pArg >= dispparams.rgvarg);
|
|
|
|
pArg->vt = *pb; // set the variant type
|
|
if (pArg->vt & VT_MFCBYREF)
|
|
{
|
|
pArg->vt &= ~VT_MFCBYREF;
|
|
pArg->vt |= VT_BYREF;
|
|
}
|
|
switch (pArg->vt)
|
|
{
|
|
case VT_I2:
|
|
#ifdef _MAC
|
|
pArg->iVal = (short)va_arg(argList, int);
|
|
#else
|
|
pArg->iVal = va_arg(argList, short);
|
|
#endif
|
|
break;
|
|
case VT_I4:
|
|
pArg->lVal = va_arg(argList, long);
|
|
break;
|
|
case VT_R4:
|
|
// Note: All float arguments to vararg functions are passed
|
|
// as doubles instead. Thats why they are passed as VT_R8
|
|
// instead of VT_R4.
|
|
pArg->vt = VT_R8;
|
|
*(DOUBLE_ARG*)&pArg->dblVal = va_arg(argList, DOUBLE_ARG);
|
|
break;
|
|
case VT_R8:
|
|
*(DOUBLE_ARG*)&pArg->dblVal = va_arg(argList, DOUBLE_ARG);
|
|
break;
|
|
case VT_DATE:
|
|
*(DOUBLE_ARG*)&pArg->date = va_arg(argList, DOUBLE_ARG);
|
|
break;
|
|
case VT_CY:
|
|
pArg->cyVal = *va_arg(argList, CY*);
|
|
break;
|
|
case VT_BSTR:
|
|
{
|
|
LPCOLESTR lpsz = va_arg(argList, LPOLESTR);
|
|
pArg->bstrVal = ::SysAllocString(lpsz);
|
|
if (lpsz != NULL && pArg->bstrVal == NULL)
|
|
AfxThrowMemoryException();
|
|
}
|
|
break;
|
|
#if !defined(_UNICODE) && !defined(OLE2ANSI)
|
|
case VT_BSTRA:
|
|
{
|
|
LPCSTR lpsz = va_arg(argList, LPSTR);
|
|
pArg->bstrVal = ::SysAllocString(T2COLE(lpsz));
|
|
if (lpsz != NULL && pArg->bstrVal == NULL)
|
|
AfxThrowMemoryException();
|
|
pArg->vt = VT_BSTR;
|
|
}
|
|
break;
|
|
#endif
|
|
case VT_DISPATCH:
|
|
pArg->pdispVal = va_arg(argList, LPDISPATCH);
|
|
break;
|
|
case VT_ERROR:
|
|
pArg->scode = va_arg(argList, SCODE);
|
|
break;
|
|
case VT_BOOL:
|
|
V_BOOL(pArg) = (VARIANT_BOOL)(va_arg(argList, BOOL) ? -1 : 0);
|
|
break;
|
|
case VT_VARIANT:
|
|
*pArg = *va_arg(argList, VARIANT*);
|
|
break;
|
|
case VT_UNKNOWN:
|
|
pArg->punkVal = va_arg(argList, LPUNKNOWN);
|
|
break;
|
|
|
|
case VT_I2|VT_BYREF:
|
|
pArg->piVal = va_arg(argList, short*);
|
|
break;
|
|
case VT_I4|VT_BYREF:
|
|
pArg->plVal = va_arg(argList, long*);
|
|
break;
|
|
case VT_R4|VT_BYREF:
|
|
pArg->pfltVal = va_arg(argList, float*);
|
|
break;
|
|
case VT_R8|VT_BYREF:
|
|
pArg->pdblVal = va_arg(argList, double*);
|
|
break;
|
|
case VT_DATE|VT_BYREF:
|
|
pArg->pdate = va_arg(argList, DATE*);
|
|
break;
|
|
case VT_CY|VT_BYREF:
|
|
pArg->pcyVal = va_arg(argList, CY*);
|
|
break;
|
|
case VT_BSTR|VT_BYREF:
|
|
pArg->pbstrVal = va_arg(argList, BSTR*);
|
|
break;
|
|
case VT_DISPATCH|VT_BYREF:
|
|
pArg->ppdispVal = va_arg(argList, LPDISPATCH*);
|
|
break;
|
|
case VT_ERROR|VT_BYREF:
|
|
pArg->pscode = va_arg(argList, SCODE*);
|
|
break;
|
|
case VT_BOOL|VT_BYREF:
|
|
{
|
|
// coerce BOOL into VARIANT_BOOL
|
|
BOOL* pboolVal = va_arg(argList, BOOL*);
|
|
#ifndef _MAC
|
|
*pboolVal = *pboolVal ? MAKELONG(-1, 0) : 0;
|
|
#else
|
|
*pboolVal = *pboolVal ? MAKELONG(0, -1) : 0;
|
|
#endif
|
|
pArg->pboolVal = (VARIANT_BOOL*)pboolVal;
|
|
}
|
|
break;
|
|
case VT_VARIANT|VT_BYREF:
|
|
pArg->pvarVal = va_arg(argList, VARIANT*);
|
|
break;
|
|
case VT_UNKNOWN|VT_BYREF:
|
|
pArg->ppunkVal = va_arg(argList, LPUNKNOWN*);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE); // unknown type!
|
|
break;
|
|
}
|
|
|
|
--pArg; // get ready to fill next argument
|
|
++pb;
|
|
}
|
|
}
|
|
|
|
// initialize return value
|
|
VARIANT* pvarResult = NULL;
|
|
VARIANT vaResult;
|
|
AfxVariantInit(&vaResult);
|
|
if (vtRet != VT_EMPTY)
|
|
pvarResult = &vaResult;
|
|
|
|
// initialize EXCEPINFO struct
|
|
EXCEPINFO excepInfo;
|
|
memset(&excepInfo, 0, sizeof excepInfo);
|
|
|
|
UINT nArgErr = (UINT)-1; // initialize to invalid arg
|
|
|
|
// make the call
|
|
SCODE sc = m_lpDispatch->Invoke(dwDispID, IID_NULL, 0, wFlags,
|
|
&dispparams, pvarResult, &excepInfo, &nArgErr);
|
|
|
|
// cleanup any arguments that need cleanup
|
|
if (dispparams.cArgs != 0)
|
|
{
|
|
VARIANT* pArg = dispparams.rgvarg + dispparams.cArgs - 1;
|
|
const BYTE* pb = pbParamInfo;
|
|
while (*pb != 0)
|
|
{
|
|
switch ((VARTYPE)*pb)
|
|
{
|
|
#if !defined(_UNICODE) && !defined(OLE2ANSI)
|
|
case VT_BSTRA:
|
|
#endif
|
|
case VT_BSTR:
|
|
VariantClear(pArg);
|
|
break;
|
|
}
|
|
--pArg;
|
|
++pb;
|
|
}
|
|
}
|
|
delete[] dispparams.rgvarg;
|
|
|
|
// throw exception on failure
|
|
if (FAILED(sc))
|
|
{
|
|
VariantClear(&vaResult);
|
|
if (sc != DISP_E_EXCEPTION)
|
|
{
|
|
// non-exception error code
|
|
AfxThrowOleException(sc);
|
|
}
|
|
|
|
// make sure excepInfo is filled in
|
|
if (excepInfo.pfnDeferredFillIn != NULL)
|
|
excepInfo.pfnDeferredFillIn(&excepInfo);
|
|
|
|
// allocate new exception, and fill it
|
|
COleDispatchException* pException =
|
|
new COleDispatchException(NULL, 0, excepInfo.wCode);
|
|
ASSERT(pException->m_wCode == excepInfo.wCode);
|
|
if (excepInfo.bstrSource != NULL)
|
|
{
|
|
pException->m_strSource = excepInfo.bstrSource;
|
|
SysFreeString(excepInfo.bstrSource);
|
|
}
|
|
if (excepInfo.bstrDescription != NULL)
|
|
{
|
|
pException->m_strDescription = excepInfo.bstrDescription;
|
|
SysFreeString(excepInfo.bstrDescription);
|
|
}
|
|
if (excepInfo.bstrHelpFile != NULL)
|
|
{
|
|
pException->m_strHelpFile = excepInfo.bstrHelpFile;
|
|
SysFreeString(excepInfo.bstrHelpFile);
|
|
}
|
|
pException->m_dwHelpContext = excepInfo.dwHelpContext;
|
|
pException->m_scError = excepInfo.scode;
|
|
|
|
// then throw the exception
|
|
THROW(pException);
|
|
ASSERT(FALSE); // not reached
|
|
}
|
|
|
|
if (vtRet != VT_EMPTY)
|
|
{
|
|
// convert return value
|
|
if (vtRet != VT_VARIANT)
|
|
{
|
|
SCODE sc = VariantChangeType(&vaResult, &vaResult, 0, vtRet);
|
|
if (FAILED(sc))
|
|
{
|
|
TRACE0("Warning: automation return value coercion failed.\n");
|
|
VariantClear(&vaResult);
|
|
AfxThrowOleException(sc);
|
|
}
|
|
ASSERT(vtRet == vaResult.vt);
|
|
}
|
|
|
|
// copy return value into return spot!
|
|
switch (vtRet)
|
|
{
|
|
case VT_I2:
|
|
*(short*)pvRet = vaResult.iVal;
|
|
break;
|
|
case VT_I4:
|
|
*(long*)pvRet = vaResult.lVal;
|
|
break;
|
|
case VT_R4:
|
|
*(_AFX_FLOAT*)pvRet = *(_AFX_FLOAT*)&vaResult.fltVal;
|
|
break;
|
|
case VT_R8:
|
|
*(_AFX_DOUBLE*)pvRet = *(_AFX_DOUBLE*)&vaResult.dblVal;
|
|
break;
|
|
case VT_DATE:
|
|
*(_AFX_DOUBLE*)pvRet = *(_AFX_DOUBLE*)&vaResult.date;
|
|
break;
|
|
case VT_CY:
|
|
*(CY*)pvRet = vaResult.cyVal;
|
|
break;
|
|
case VT_BSTR:
|
|
AfxBSTR2CString((CString*)pvRet, vaResult.bstrVal);
|
|
SysFreeString(vaResult.bstrVal);
|
|
break;
|
|
case VT_DISPATCH:
|
|
*(LPDISPATCH*)pvRet = vaResult.pdispVal;
|
|
break;
|
|
case VT_ERROR:
|
|
*(SCODE*)pvRet = vaResult.scode;
|
|
break;
|
|
case VT_BOOL:
|
|
*(BOOL*)pvRet = (V_BOOL(&vaResult) != 0);
|
|
break;
|
|
case VT_VARIANT:
|
|
*(VARIANT*)pvRet = vaResult;
|
|
break;
|
|
case VT_UNKNOWN:
|
|
*(LPUNKNOWN*)pvRet = vaResult.punkVal;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE); // invalid return type specified
|
|
}
|
|
}
|
|
}
|
|
|
|
void AFX_CDECL COleDispatchDriver::InvokeHelper(DISPID dwDispID, WORD wFlags,
|
|
VARTYPE vtRet, void* pvRet, const BYTE* pbParamInfo, ...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, pbParamInfo);
|
|
|
|
InvokeHelperV(dwDispID, wFlags, vtRet, pvRet, pbParamInfo, argList);
|
|
|
|
va_end(argList);
|
|
}
|
|
|
|
void COleDispatchDriver::GetProperty(DISPID dwDispID, VARTYPE vtProp,
|
|
void* pvProp) const
|
|
{
|
|
((COleDispatchDriver*)this)->InvokeHelper(dwDispID,
|
|
DISPATCH_PROPERTYGET, vtProp, pvProp, NULL);
|
|
}
|
|
|
|
void AFX_CDECL COleDispatchDriver::SetProperty(DISPID dwDispID, VARTYPE vtProp, ...)
|
|
{
|
|
va_list argList; // really only one arg, but...
|
|
va_start(argList, vtProp);
|
|
#ifdef _MAC
|
|
argList -= 2;
|
|
#endif
|
|
|
|
BYTE rgbParams[2];
|
|
if (vtProp & VT_BYREF)
|
|
{
|
|
vtProp &= ~VT_BYREF;
|
|
vtProp |= VT_MFCBYREF;
|
|
}
|
|
|
|
#if !defined(_UNICODE) && !defined(OLE2ANSI)
|
|
if (vtProp == VT_BSTR)
|
|
vtProp = VT_BSTRA;
|
|
#endif
|
|
|
|
rgbParams[0] = (BYTE)vtProp;
|
|
rgbParams[1] = 0;
|
|
WORD wFlags = (WORD)(vtProp == VT_DISPATCH ?
|
|
DISPATCH_PROPERTYPUTREF : DISPATCH_PROPERTYPUT);
|
|
InvokeHelperV(dwDispID, wFlags, VT_EMPTY, NULL, rgbParams, argList);
|
|
|
|
va_end(argList);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|