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.
583 lines
12 KiB
583 lines
12 KiB
/*
|
|
|
|
File: Dispatch.cpp
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation. All Rights Reserved.
|
|
|
|
Abstract:
|
|
Dispatch helpers. stolen from HTMED tree
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "resource.h"
|
|
#include "dispatch.h"
|
|
|
|
//#include "viewhdrs.h"
|
|
|
|
#define RETURN return
|
|
#define SetLastError(x,y) SetLastError(x)
|
|
|
|
HRESULT
|
|
CallDispatchMethod(
|
|
IDispatch * pDisp,
|
|
DISPID dispid,
|
|
VARIANT * pvarFirst,
|
|
char * pstrSig,
|
|
va_list val)
|
|
{
|
|
HRESULT hr;
|
|
int c;
|
|
int i;
|
|
VARIANT * pvar;
|
|
VARIANT * pvarOut = NULL;
|
|
VARIANT avar[10];
|
|
VARIANT varOut;
|
|
void * pvOut = NULL;
|
|
DISPPARAMS dp;
|
|
EXCEPINFO ei;
|
|
UINT uArgErr;
|
|
|
|
_ASSERTE(pDisp);
|
|
|
|
VariantInit(&varOut);
|
|
|
|
if (pstrSig)
|
|
{
|
|
c = strlen(pstrSig);
|
|
//_ASSERTE(c > 0);
|
|
//_ASSERTE(c <= DIM(avar));
|
|
|
|
if (pstrSig[c - 1] & VTS_RETURN_FLAG)
|
|
{
|
|
pvarOut = &varOut;
|
|
c--;
|
|
}
|
|
|
|
for (i = 0, pvar = avar + c - 1; i < c; i++, pvar--)
|
|
{
|
|
pvar->vt = pstrSig[i];
|
|
switch (pstrSig[i])
|
|
{
|
|
case VT_I2:
|
|
pvar->iVal = va_arg(val, short);
|
|
break;
|
|
|
|
case VT_I4:
|
|
pvar->lVal = va_arg(val, long);
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
pvar->bstrVal = va_arg(val, BSTR);
|
|
break;
|
|
|
|
case VT_DISPATCH:
|
|
pvar->pdispVal = va_arg(val, IDispatch *);
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
pvar->punkVal = va_arg(val, IUnknown *);
|
|
break;
|
|
|
|
case VT_BOOL:
|
|
pvar->boolVal = va_arg(val, VARIANT_BOOL);
|
|
break;
|
|
|
|
case VT_BSTR | VTS_BYREF_FLAG:
|
|
case VT_DISPATCH | VTS_BYREF_FLAG:
|
|
case VT_UNKNOWN | VTS_BYREF_FLAG:
|
|
pvar->vt = (VARTYPE)((pstrSig[i] & (VTS_BYREF_FLAG - 1)) | VT_BYREF);
|
|
pvar->ppdispVal = va_arg(val, IDispatch **);
|
|
|
|
// Passing an uninitialized BSTR or object will crash when the callee
|
|
// frees the existing value as it's supposed to.
|
|
// This has been a common source of hard-to-find bugs, but
|
|
// this _ASSERTE can be removed if we need to pass an in/out string.
|
|
_ASSERTE(*pvar->ppdispVal == NULL);
|
|
break;
|
|
|
|
case VT_I2 | VTS_BYREF_FLAG:
|
|
case VT_I4 | VTS_BYREF_FLAG:
|
|
case VT_BOOL | VTS_BYREF_FLAG:
|
|
case VT_VARIANT | VTS_BYREF_FLAG:
|
|
pvar->vt = (VARTYPE)((pstrSig[i] & (VTS_BYREF_FLAG - 1)) | VT_BYREF);
|
|
pvar->ppdispVal = va_arg(val, IDispatch **);
|
|
break;
|
|
|
|
default:
|
|
_ASSERTE(FALSE && "Unsupported variant type");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pvarOut)
|
|
{
|
|
pvOut = va_arg(val, void *);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
c = 0;
|
|
}
|
|
|
|
if (pvarFirst)
|
|
{
|
|
// _ASSERTE(c >= 0);
|
|
// _ASSERTE(c < DIM(avar));
|
|
avar[c++] = *pvarFirst;
|
|
}
|
|
|
|
dp.rgvarg = avar;
|
|
dp.cArgs = c;
|
|
dp.rgdispidNamedArgs = NULL;
|
|
dp.cNamedArgs = 0;
|
|
|
|
memset(&ei, 0, sizeof (ei));
|
|
|
|
hr = pDisp->Invoke(
|
|
dispid,
|
|
IID_NULL,
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
DISPATCH_METHOD,
|
|
&dp,
|
|
pvarOut,
|
|
&ei,
|
|
&uArgErr);
|
|
if (hr)
|
|
{
|
|
SetLastError(hr, &ei);
|
|
goto Error;
|
|
}
|
|
|
|
// If we're returning a value, coerce it to the correct
|
|
// type
|
|
|
|
if (pvarOut)
|
|
{
|
|
#pragma warning(disable: 4310) // cast truncates constant value
|
|
hr = VariantChangeTypeEx(
|
|
&varOut,
|
|
&varOut,
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
0,
|
|
(VARTYPE)(pstrSig[c] & (char) ~VTS_RETURN_FLAG));
|
|
#pragma warning(default: 4310) // cast truncates constant value
|
|
if (hr)
|
|
goto Error;
|
|
|
|
#pragma warning(disable: 4310) // cast truncates constant value
|
|
switch (pstrSig[c] & (char) ~VTS_RETURN_FLAG)
|
|
#pragma warning(default: 4310) // cast truncates constant value
|
|
{
|
|
case VT_I2:
|
|
* (short *) pvOut = varOut.iVal;
|
|
break;
|
|
|
|
case VT_I4:
|
|
* (long *) pvOut = varOut.lVal;
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
* (BSTR *) pvOut = varOut.bstrVal;
|
|
break;
|
|
|
|
case VT_DISPATCH:
|
|
* (IDispatch **) pvOut = varOut.pdispVal;
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
* (IUnknown **) pvOut = varOut.punkVal;
|
|
break;
|
|
|
|
case VT_BOOL:
|
|
* (VARIANT_BOOL *) pvOut = varOut.boolVal;
|
|
break;
|
|
|
|
default:
|
|
_ASSERTE(FALSE && "Unsupported type");
|
|
break;
|
|
}
|
|
|
|
varOut.vt = VT_EMPTY;
|
|
}
|
|
|
|
Error:
|
|
VariantClear(&varOut);
|
|
|
|
RETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT __cdecl
|
|
CallDispatchMethod(IDispatch * pDisp, DISPID dispid, char * pstrSig, ...)
|
|
{
|
|
HRESULT hr;
|
|
va_list val;
|
|
|
|
va_start(val, pstrSig);
|
|
|
|
hr = CallDispatchMethod(pDisp, dispid, NULL, pstrSig, val);
|
|
|
|
va_end(val);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CallDispatchMethod(
|
|
IDispatch * pDisp,
|
|
WCHAR * pstrMethod,
|
|
VARIANT * pvarFirst,
|
|
char * pstrSig,
|
|
va_list val)
|
|
{
|
|
HRESULT hr;
|
|
DISPID dispid;
|
|
|
|
// NOTE that depending on the dispatch implementation, this
|
|
// method call can fail with more than one error code
|
|
// (notably DISP_E_MEMBERNOTFOUND and TYPE_E_ELEMENTNOTFOUND,
|
|
// including others). Since we want to reliably detect a
|
|
// missing method, we map all errors to DISP_E_MEMBERNOTFOUND.
|
|
|
|
hr = pDisp->GetIDsOfNames(
|
|
IID_NULL,
|
|
&pstrMethod,
|
|
1,
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
&dispid);
|
|
if (hr)
|
|
{
|
|
#if DBG == 1
|
|
switch (hr)
|
|
{
|
|
case DISP_E_MEMBERNOTFOUND:
|
|
case DISP_E_UNKNOWNNAME:
|
|
case TYPE_E_ELEMENTNOTFOUND:
|
|
case E_NOTIMPL:
|
|
case RPC_E_SERVER_DIED:
|
|
break;
|
|
|
|
default:
|
|
_ASSERTE(FALSE && "Unexpected error code from GetIDsOfNames.");
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
hr = DISP_E_MEMBERNOTFOUND;
|
|
goto Error;
|
|
}
|
|
|
|
hr = CallDispatchMethod(pDisp, dispid, pvarFirst, pstrSig, val);
|
|
if (hr)
|
|
goto Error;
|
|
|
|
Error:
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT __cdecl
|
|
CallDispatchMethod(
|
|
IDispatch * pDisp,
|
|
WCHAR * pstrMethod,
|
|
char * pstrSig,
|
|
...)
|
|
{
|
|
HRESULT hr;
|
|
va_list val;
|
|
|
|
va_start(val, pstrSig);
|
|
|
|
hr = CallDispatchMethod(pDisp, pstrMethod, NULL, pstrSig, val);
|
|
|
|
va_end(val);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT __cdecl
|
|
CallDispatchMethod(
|
|
IDispatch * pDisp,
|
|
WCHAR * pstrMethod,
|
|
VARIANT * pvarFirst,
|
|
char * pstrSig,
|
|
...)
|
|
{
|
|
HRESULT hr;
|
|
va_list val;
|
|
|
|
va_start(val, pstrSig);
|
|
|
|
hr = CallDispatchMethod(pDisp, pstrMethod, pvarFirst, pstrSig, val);
|
|
|
|
va_end(val);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetDispatchProperty(
|
|
IDispatch * pDisp,
|
|
WCHAR * pstrProperty,
|
|
VARENUM vt,
|
|
void * pv)
|
|
{
|
|
HRESULT hr;
|
|
DISPID dispid;
|
|
|
|
hr = pDisp->GetIDsOfNames(
|
|
IID_NULL,
|
|
&pstrProperty,
|
|
1,
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
&dispid);
|
|
if (hr)
|
|
{
|
|
#if DBG == 1
|
|
switch (hr)
|
|
{
|
|
case DISP_E_MEMBERNOTFOUND:
|
|
case DISP_E_UNKNOWNNAME:
|
|
case TYPE_E_ELEMENTNOTFOUND:
|
|
case E_NOTIMPL:
|
|
break;
|
|
|
|
default:
|
|
_ASSERTE(FALSE && "Unexpected error code from GetIDsOfNames.");
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
RETURN(DISP_E_MEMBERNOTFOUND);
|
|
}
|
|
|
|
return GetDispatchProperty(pDisp, dispid, vt, pv);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetDispatchProperty(
|
|
IDispatch * pDisp,
|
|
DISPID dispidProperty,
|
|
VARENUM vt,
|
|
void * pv)
|
|
{
|
|
HRESULT hr;
|
|
VARIANT var;
|
|
DISPPARAMS dp = { NULL, NULL, 0, 0 };
|
|
EXCEPINFO ei;
|
|
UINT uArgErr;
|
|
|
|
#if DBG == 1
|
|
switch (vt)
|
|
{
|
|
case VT_I4:
|
|
case VT_DISPATCH:
|
|
case VT_UNKNOWN:
|
|
case VT_BSTR:
|
|
break;
|
|
|
|
}
|
|
#endif
|
|
|
|
VariantInit(&var);
|
|
|
|
hr = pDisp->Invoke(
|
|
dispidProperty,
|
|
IID_NULL,
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
DISPATCH_PROPERTYGET|DISPATCH_METHOD,
|
|
&dp,
|
|
&var,
|
|
&ei,
|
|
&uArgErr);
|
|
if (hr)
|
|
goto Error;
|
|
|
|
if (vt != VT_VARIANT)
|
|
{
|
|
hr = VariantChangeTypeEx(
|
|
&var,
|
|
&var,
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
0,
|
|
(VARTYPE)vt);
|
|
if (hr)
|
|
goto Error;
|
|
}
|
|
|
|
switch (vt)
|
|
{
|
|
case VT_I2:
|
|
* (short *) pv = var.iVal;
|
|
break;
|
|
|
|
case VT_I4:
|
|
* (int *) pv = var.lVal;
|
|
break;
|
|
|
|
case VT_DISPATCH:
|
|
* (IDispatch **) pv = var.pdispVal;
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
* (IUnknown **) pv = var.punkVal;
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
* (BSTR *) pv = var.bstrVal;
|
|
break;
|
|
|
|
case VT_BOOL:
|
|
* (VARIANT_BOOL *) pv = var.boolVal;
|
|
break;
|
|
case VT_VARIANT:
|
|
VariantCopy( (VARIANT *) pv, &var);
|
|
break;
|
|
default:
|
|
_ASSERTE(FALSE && "Unsupported type");
|
|
break;
|
|
}
|
|
|
|
Error:
|
|
RETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
PutDispatchProperty(
|
|
IDispatch * pDisp,
|
|
DISPID dispidProperty,
|
|
VARENUM vt,
|
|
va_list val)
|
|
{
|
|
VARIANT var;
|
|
DISPPARAMS dp;
|
|
EXCEPINFO ei;
|
|
UINT uArgErr;
|
|
DISPID dispidPropertyPut = DISPID_PROPERTYPUT;
|
|
|
|
var.vt = (VARTYPE)vt;
|
|
switch (vt)
|
|
{
|
|
case VT_I2:
|
|
var.iVal = va_arg(val, short);
|
|
break;
|
|
|
|
case VT_I4:
|
|
var.lVal = va_arg(val, int);
|
|
break;
|
|
|
|
case VT_DISPATCH:
|
|
var.pdispVal = va_arg(val, IDispatch *);
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
var.punkVal = va_arg(val, IUnknown *);
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
var.bstrVal = va_arg(val, BSTR);
|
|
break;
|
|
|
|
case VT_BOOL:
|
|
var.boolVal = va_arg(val, VARIANT_BOOL);
|
|
break;
|
|
case VT_VARIANT:
|
|
VariantCopy(&var, &(va_arg(val, VARIANT)));
|
|
break;
|
|
default:
|
|
_ASSERTE(FALSE && "Unsupported type");
|
|
break;
|
|
}
|
|
|
|
dp.rgvarg = &var;
|
|
dp.cArgs = 1;
|
|
dp.cNamedArgs = 1;
|
|
dp.rgdispidNamedArgs = &dispidPropertyPut;
|
|
|
|
RETURN(pDisp->Invoke(
|
|
dispidProperty,
|
|
IID_NULL,
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
DISPATCH_PROPERTYPUT,
|
|
&dp,
|
|
NULL,
|
|
&ei,
|
|
&uArgErr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
__cdecl
|
|
PutDispatchProperty(
|
|
IDispatch * pDisp,
|
|
DISPID dispidProperty,
|
|
VARENUM vt,
|
|
...)
|
|
{
|
|
HRESULT hr;
|
|
va_list val;
|
|
|
|
va_start(val, vt);
|
|
|
|
hr = PutDispatchProperty(pDisp, dispidProperty, vt, val);
|
|
|
|
va_end(val);
|
|
|
|
RETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
__cdecl
|
|
PutDispatchProperty(
|
|
IDispatch * pDisp,
|
|
WCHAR * pstrProperty,
|
|
VARENUM vt,
|
|
...)
|
|
{
|
|
HRESULT hr;
|
|
DISPID dispid;
|
|
va_list val;
|
|
|
|
hr = pDisp->GetIDsOfNames(
|
|
IID_NULL,
|
|
&pstrProperty,
|
|
1,
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
&dispid);
|
|
if (hr)
|
|
{
|
|
#if DBG == 1
|
|
switch (hr)
|
|
{
|
|
case DISP_E_MEMBERNOTFOUND:
|
|
case DISP_E_UNKNOWNNAME:
|
|
case TYPE_E_ELEMENTNOTFOUND:
|
|
case E_NOTIMPL:
|
|
break;
|
|
|
|
default:
|
|
_ASSERTE(FALSE && "Unexpected error code from GetIDsOfNames.");
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
RETURN(DISP_E_MEMBERNOTFOUND);
|
|
}
|
|
|
|
va_start(val, vt);
|
|
|
|
hr = PutDispatchProperty(pDisp, dispid, vt, val);
|
|
|
|
va_end(val);
|
|
|
|
RETURN(hr);
|
|
}
|
|
|