452 lines
15 KiB
C
452 lines
15 KiB
C
/**
|
|
* Dispatch API functions
|
|
*
|
|
* Copyright 2000 Francois Jacques, Macadamian Technologies Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
|
|
#define COBJMACROS
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "objbase.h"
|
|
#include "oleauto.h"
|
|
#include "winerror.h"
|
|
#include "winreg.h"
|
|
#include "winnls.h" /* for PRIMARYLANGID */
|
|
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
|
|
|
static IDispatch * WINAPI StdDispatch_Construct(IUnknown * punkOuter, void * pvThis, ITypeInfo * pTypeInfo);
|
|
|
|
/******************************************************************************
|
|
* DispInvoke (OLEAUT32.30)
|
|
*
|
|
* Call an object method using the information from its type library.
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: Returns DISP_E_EXCEPTION and updates pexcepinfo if an exception occurs.
|
|
* DISP_E_BADPARAMCOUNT if the number of parameters is incorrect.
|
|
* DISP_E_MEMBERNOTFOUND if the method does not exist.
|
|
* puArgErr is updated if a parameter error (see notes) occurs.
|
|
* Otherwise, returns the result of calling ITypeInfo_Invoke().
|
|
*
|
|
* NOTES
|
|
* Parameter errors include the following:
|
|
*| DISP_E_BADVARTYPE
|
|
*| E_INVALIDARG An argument was invalid
|
|
*| DISP_E_TYPEMISMATCH,
|
|
*| DISP_E_OVERFLOW An argument was valid but could not be coerced
|
|
*| DISP_E_PARAMNOTOPTIONAL A non optional parameter was not passed
|
|
*| DISP_E_PARAMNOTFOUND A parameter was passed that was not expected by the method
|
|
* This call defers to ITypeInfo_Invoke().
|
|
*/
|
|
HRESULT WINAPI DispInvoke(
|
|
VOID *_this, /* [in] Object to call method on */
|
|
ITypeInfo *ptinfo, /* [in] Object type info */
|
|
DISPID dispidMember, /* [in] DISPID of the member (e.g. from GetIDsOfNames()) */
|
|
USHORT wFlags, /* [in] Kind of method call (DISPATCH_ flags from "oaidl.h") */
|
|
DISPPARAMS *pparams, /* [in] Array of method arguments */
|
|
VARIANT *pvarResult, /* [out] Destination for the result of the call */
|
|
EXCEPINFO *pexcepinfo, /* [out] Destination for exception information */
|
|
UINT *puArgErr) /* [out] Destination for bad argument */
|
|
{
|
|
TRACE("\n");
|
|
|
|
return ITypeInfo_Invoke(ptinfo, _this, dispidMember, wFlags,
|
|
pparams, pvarResult, pexcepinfo, puArgErr);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* DispGetIDsOfNames (OLEAUT32.29)
|
|
*
|
|
* Convert a set of parameter names to DISPIDs for DispInvoke().
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: An HRESULT error code.
|
|
*
|
|
* NOTES
|
|
* This call defers to ITypeInfo_GetIDsOfNames(). The ITypeInfo interface passed
|
|
* as ptinfo contains the information to map names to DISPIDs.
|
|
*/
|
|
HRESULT WINAPI DispGetIDsOfNames(
|
|
ITypeInfo *ptinfo, /* [in] Object's type info */
|
|
OLECHAR **rgszNames, /* [in] Array of names to get DISPIDs for */
|
|
UINT cNames, /* [in] Number of names in rgszNames */
|
|
DISPID *rgdispid) /* [out] Destination for converted DISPIDs */
|
|
{
|
|
return ITypeInfo_GetIDsOfNames(ptinfo, rgszNames, cNames, rgdispid);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* DispGetParam (OLEAUT32.28)
|
|
*
|
|
* Retrieve a parameter from a DISPPARAMS structure and coerce it to the
|
|
* specified variant type.
|
|
*
|
|
* NOTES
|
|
* Coercion is done using system (0) locale.
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: DISP_E_PARAMNOTFOUND, if position is invalid. or
|
|
* DISP_E_TYPEMISMATCH, if the coercion failed. puArgErr is
|
|
* set to the index of the argument in pdispparams.
|
|
*/
|
|
HRESULT WINAPI DispGetParam(
|
|
DISPPARAMS *pdispparams, /* [in] Parameter list */
|
|
UINT position, /* [in] Position of parameter to coerce in pdispparams */
|
|
VARTYPE vtTarg, /* [in] Type of value to coerce to */
|
|
VARIANT *pvarResult, /* [out] Destination for resulting variant */
|
|
UINT *puArgErr) /* [out] Destination for error code */
|
|
{
|
|
/* position is counted backwards */
|
|
UINT pos;
|
|
HRESULT hr;
|
|
|
|
TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
|
|
position, pdispparams->cArgs, pdispparams->cNamedArgs);
|
|
if (position < pdispparams->cArgs) {
|
|
/* positional arg? */
|
|
pos = pdispparams->cArgs - position - 1;
|
|
} else {
|
|
/* FIXME: is this how to handle named args? */
|
|
for (pos=0; pos<pdispparams->cNamedArgs; pos++)
|
|
if (pdispparams->rgdispidNamedArgs[pos] == position) break;
|
|
|
|
if (pos==pdispparams->cNamedArgs)
|
|
return DISP_E_PARAMNOTFOUND;
|
|
}
|
|
hr = VariantChangeType(pvarResult,
|
|
&pdispparams->rgvarg[pos],
|
|
0, vtTarg);
|
|
if (hr == DISP_E_TYPEMISMATCH) *puArgErr = pos;
|
|
return hr;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* CreateStdDispatch [OLEAUT32.32]
|
|
*
|
|
* Create and return a standard IDispatch object.
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK. ppunkStdDisp contains the new object.
|
|
* Failure: An HRESULT error code.
|
|
*
|
|
* NOTES
|
|
* Outer unknown appears to be completely ignored.
|
|
*/
|
|
HRESULT WINAPI CreateStdDispatch(
|
|
IUnknown* punkOuter,
|
|
void* pvThis,
|
|
ITypeInfo* ptinfo,
|
|
IUnknown** ppunkStdDisp)
|
|
{
|
|
TRACE("(%p, %p, %p, %p)\n", punkOuter, pvThis, ptinfo, ppunkStdDisp);
|
|
|
|
*ppunkStdDisp = (LPUNKNOWN)StdDispatch_Construct(punkOuter, pvThis, ptinfo);
|
|
if (!*ppunkStdDisp)
|
|
return E_OUTOFMEMORY;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* IDispatch {OLEAUT32}
|
|
*
|
|
* NOTES
|
|
* The IDispatch interface provides a single interface to dispatch method calls,
|
|
* regardless of whether the object to be called is in or out of process,
|
|
* local or remote (e.g. being called over a network). This interface is late-bound
|
|
* (linked at run-time), as opposed to early-bound (linked at compile time).
|
|
*
|
|
* The interface is used by objects that wish to called by scripting
|
|
* languages such as VBA, in order to minimise the amount of COM and C/C++
|
|
* knowledge required, or by objects that wish to live out of process from code
|
|
* that will call their methods.
|
|
*
|
|
* Method, property and parameter names can be localised. The details required to
|
|
* map names to methods and parameters are collected in a type library, usually
|
|
* output by an IDL compiler using the objects IDL description. This information is
|
|
* accessible programatically through the ITypeLib interface (for a type library),
|
|
* and the ITypeInfo interface (for an object within the type library). Type information
|
|
* can also be created at run-time using CreateDispTypeInfo().
|
|
*
|
|
* WRAPPERS
|
|
* Instead of using IDispatch directly, there are several wrapper functions available
|
|
* to simplify the process of calling an objects methods through IDispatch.
|
|
*
|
|
* A standard implementation of an IDispatch object is created by calling
|
|
* CreateStdDispatch(). Numeric Id values for the parameters and methods (DISPIDs)
|
|
* of an object of interest are retrieved by calling DispGetIDsOfNames(). DispGetParam()
|
|
* retrieves information about a particular parameter. Finally the DispInvoke()
|
|
* function is responsible for actually calling methods on an object.
|
|
*
|
|
* METHODS
|
|
*/
|
|
|
|
typedef struct
|
|
{
|
|
const IDispatchVtbl *lpVtbl;
|
|
void * pvThis;
|
|
ITypeInfo * pTypeInfo;
|
|
LONG ref;
|
|
} StdDispatch;
|
|
|
|
/******************************************************************************
|
|
* IDispatch_QueryInterface {OLEAUT32}
|
|
*
|
|
* See IUnknown_QueryInterface.
|
|
*/
|
|
static HRESULT WINAPI StdDispatch_QueryInterface(
|
|
LPDISPATCH iface,
|
|
REFIID riid,
|
|
void** ppvObject)
|
|
{
|
|
StdDispatch *This = (StdDispatch *)iface;
|
|
TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
|
|
|
|
if (IsEqualIID(riid, &IID_IDispatch) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*ppvObject = (LPVOID)This;
|
|
IUnknown_AddRef((LPUNKNOWN)*ppvObject);
|
|
return S_OK;
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* IDispatch_AddRef {OLEAUT32}
|
|
*
|
|
* See IUnknown_AddRef.
|
|
*/
|
|
static ULONG WINAPI StdDispatch_AddRef(LPDISPATCH iface)
|
|
{
|
|
StdDispatch *This = (StdDispatch *)iface;
|
|
ULONG refCount = InterlockedIncrement(&This->ref);
|
|
|
|
TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1);
|
|
|
|
return refCount;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* IDispatch_Release {OLEAUT32}
|
|
*
|
|
* See IUnknown_Release.
|
|
*/
|
|
static ULONG WINAPI StdDispatch_Release(LPDISPATCH iface)
|
|
{
|
|
StdDispatch *This = (StdDispatch *)iface;
|
|
ULONG refCount = InterlockedDecrement(&This->ref);
|
|
|
|
TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1);
|
|
|
|
if (!refCount)
|
|
{
|
|
ITypeInfo_Release(This->pTypeInfo);
|
|
CoTaskMemFree(This);
|
|
}
|
|
|
|
return refCount;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* IDispatch_GetTypeInfoCount {OLEAUT32}
|
|
*
|
|
* Get the count of type information in an IDispatch interface.
|
|
*
|
|
* PARAMS
|
|
* iface [I] IDispatch interface
|
|
* pctinfo [O] Destination for the count
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK. pctinfo is updated with the count. This is always 1 if
|
|
* the object provides type information, and 0 if it does not.
|
|
* Failure: E_NOTIMPL. The object does not provide type information.
|
|
*
|
|
* NOTES
|
|
* See IDispatch() and IDispatch_GetTypeInfo().
|
|
*/
|
|
static HRESULT WINAPI StdDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo)
|
|
{
|
|
StdDispatch *This = (StdDispatch *)iface;
|
|
TRACE("(%p)\n", pctinfo);
|
|
|
|
*pctinfo = This->pTypeInfo ? 1 : 0;
|
|
return S_OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* IDispatch_GetTypeInfo {OLEAUT32}
|
|
*
|
|
* Get type information from an IDispatch interface.
|
|
*
|
|
* PARAMS
|
|
* iface [I] IDispatch interface
|
|
* iTInfo [I] Index of type information.
|
|
* lcid [I] Locale of the type information to get
|
|
* ppTInfo [O] Destination for the ITypeInfo object
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK. ppTInfo is updated with the objects type information
|
|
* Failure: DISP_E_BADINDEX, if iTInfo is any value other than 0.
|
|
*
|
|
* NOTES
|
|
* See IDispatch.
|
|
*/
|
|
static HRESULT WINAPI StdDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
|
|
{
|
|
StdDispatch *This = (StdDispatch *)iface;
|
|
TRACE("(%d, %lx, %p)\n", iTInfo, lcid, ppTInfo);
|
|
|
|
*ppTInfo = NULL;
|
|
if (iTInfo != 0)
|
|
return DISP_E_BADINDEX;
|
|
|
|
if (This->pTypeInfo)
|
|
{
|
|
*ppTInfo = This->pTypeInfo;
|
|
ITypeInfo_AddRef(*ppTInfo);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* IDispatch_GetIDsOfNames {OLEAUT32}
|
|
*
|
|
* Convert a methods name and an optional set of parameter names into DISPIDs
|
|
* for passing to IDispatch_Invoke().
|
|
*
|
|
* PARAMS
|
|
* iface [I] IDispatch interface
|
|
* riid [I] Reserved, set to IID_NULL
|
|
* rgszNames [I] Name to convert
|
|
* cNames [I] Number of names in rgszNames
|
|
* lcid [I] Locale of the type information to convert from
|
|
* rgDispId [O] Destination for converted DISPIDs.
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: DISP_E_UNKNOWNNAME, if any of the names is invalid.
|
|
* DISP_E_UNKNOWNLCID if lcid is invalid.
|
|
* Otherwise, an An HRESULT error code.
|
|
*
|
|
* NOTES
|
|
* This call defers to ITypeInfo_GetIDsOfNames(), using the ITypeInfo object
|
|
* contained within the IDispatch object.
|
|
* The first member of the names list must be a method name. The names following
|
|
* the method name are the parameters for that method.
|
|
*/
|
|
static HRESULT WINAPI StdDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
|
|
{
|
|
StdDispatch *This = (StdDispatch *)iface;
|
|
TRACE("(%s, %p, %d, 0x%lx, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
|
|
|
|
if (!IsEqualGUID(riid, &IID_NULL))
|
|
{
|
|
FIXME(" expected riid == IID_NULL\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
return DispGetIDsOfNames(This->pTypeInfo, rgszNames, cNames, rgDispId);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* IDispatch_Invoke {OLEAUT32}
|
|
*
|
|
* Call an object method.
|
|
*
|
|
* PARAMS
|
|
* iface [I] IDispatch interface
|
|
* dispIdMember [I] DISPID of the method (from GetIDsOfNames())
|
|
* riid [I] Reserved, set to IID_NULL
|
|
* lcid [I] Locale of the type information to convert parameters with
|
|
* wFlags, [I] Kind of method call (DISPATCH_ flags from "oaidl.h")
|
|
* pDispParams [I] Array of method arguments
|
|
* pVarResult [O] Destination for the result of the call
|
|
* pExcepInfo [O] Destination for exception information
|
|
* puArgErr [O] Destination for bad argument
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: See DispInvoke() for failure cases.
|
|
*
|
|
* NOTES
|
|
* See DispInvoke() and IDispatch().
|
|
*/
|
|
static HRESULT WINAPI StdDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid,
|
|
WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult,
|
|
EXCEPINFO * pExcepInfo, UINT * puArgErr)
|
|
{
|
|
StdDispatch *This = (StdDispatch *)iface;
|
|
TRACE("(%ld, %s, 0x%lx, 0x%x, %p, %p, %p, %p)\n", dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
|
|
|
|
if (!IsEqualGUID(riid, &IID_NULL))
|
|
{
|
|
FIXME(" expected riid == IID_NULL\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
return DispInvoke(This->pvThis, This->pTypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
|
|
}
|
|
|
|
static const IDispatchVtbl StdDispatch_VTable =
|
|
{
|
|
StdDispatch_QueryInterface,
|
|
StdDispatch_AddRef,
|
|
StdDispatch_Release,
|
|
StdDispatch_GetTypeInfoCount,
|
|
StdDispatch_GetTypeInfo,
|
|
StdDispatch_GetIDsOfNames,
|
|
StdDispatch_Invoke
|
|
};
|
|
|
|
static IDispatch * WINAPI StdDispatch_Construct(
|
|
IUnknown * punkOuter,
|
|
void * pvThis,
|
|
ITypeInfo * pTypeInfo)
|
|
{
|
|
StdDispatch * pStdDispatch;
|
|
|
|
pStdDispatch = CoTaskMemAlloc(sizeof(StdDispatch));
|
|
if (!pStdDispatch)
|
|
return (IDispatch *)pStdDispatch;
|
|
|
|
pStdDispatch->lpVtbl = &StdDispatch_VTable;
|
|
pStdDispatch->pvThis = pvThis;
|
|
pStdDispatch->pTypeInfo = pTypeInfo;
|
|
pStdDispatch->ref = 1;
|
|
|
|
/* we keep a reference to the type info so prevent it from
|
|
* being destroyed until we are done with it */
|
|
ITypeInfo_AddRef(pTypeInfo);
|
|
|
|
return (IDispatch *)pStdDispatch;
|
|
}
|