| /** | |
| * 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 "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(ole); | |
| /****************************************************************************** | |
| * 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; | |
| } | |
| if (pdispparams->cArgs > 0 && !pdispparams->rgvarg) | |
| { | |
| hr = E_INVALIDARG; | |
| goto done; | |
| } | |
| if (!pvarResult) | |
| { | |
| hr = E_INVALIDARG; | |
| goto done; | |
| } | |
| hr = VariantChangeType(pvarResult, | |
| &pdispparams->rgvarg[pos], | |
| 0, vtTarg); | |
| done: | |
| if (FAILED(hr)) | |
| *puArgErr = pos; | |
| return hr; | |
| } | |
| /****************************************************************************** | |
| * 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 programmatically 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 | |
| { | |
| IDispatch IDispatch_iface; | |
| void * pvThis; | |
| ITypeInfo * pTypeInfo; | |
| LONG ref; | |
| } StdDispatch; | |
| static inline StdDispatch *impl_from_IDispatch(IDispatch *iface) | |
| { | |
| return CONTAINING_RECORD(iface, StdDispatch, IDispatch_iface); | |
| } | |
| /****************************************************************************** | |
| * IDispatch_QueryInterface {OLEAUT32} | |
| * | |
| * See IUnknown_QueryInterface. | |
| */ | |
| static HRESULT WINAPI StdDispatch_QueryInterface( | |
| LPDISPATCH iface, | |
| REFIID riid, | |
| void** ppvObject) | |
| { | |
| StdDispatch *This = impl_from_IDispatch(iface); | |
| TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); | |
| *ppvObject = NULL; | |
| if (IsEqualIID(riid, &IID_IDispatch) || | |
| IsEqualIID(riid, &IID_IUnknown)) | |
| { | |
| *ppvObject = iface; | |
| IDispatch_AddRef(iface); | |
| return S_OK; | |
| } | |
| return E_NOINTERFACE; | |
| } | |
| /****************************************************************************** | |
| * IDispatch_AddRef {OLEAUT32} | |
| * | |
| * See IUnknown_AddRef. | |
| */ | |
| static ULONG WINAPI StdDispatch_AddRef(LPDISPATCH iface) | |
| { | |
| StdDispatch *This = impl_from_IDispatch(iface); | |
| ULONG refCount = InterlockedIncrement(&This->ref); | |
| TRACE("(%p)->(ref before=%u)\n",This, refCount - 1); | |
| return refCount; | |
| } | |
| /****************************************************************************** | |
| * IDispatch_Release {OLEAUT32} | |
| * | |
| * See IUnknown_Release. | |
| */ | |
| static ULONG WINAPI StdDispatch_Release(LPDISPATCH iface) | |
| { | |
| StdDispatch *This = impl_from_IDispatch(iface); | |
| ULONG refCount = InterlockedDecrement(&This->ref); | |
| TRACE("(%p)->(ref before=%u)\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) | |
| { | |
| TRACE("(%p)\n", pctinfo); | |
| *pctinfo = 1; | |
| 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 = impl_from_IDispatch(iface); | |
| TRACE("(%d, %x, %p)\n", iTInfo, lcid, ppTInfo); | |
| *ppTInfo = NULL; | |
| if (iTInfo != 0) | |
| return DISP_E_BADINDEX; | |
| *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 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 = impl_from_IDispatch(iface); | |
| TRACE("(%s, %p, %d, 0x%x, %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 = impl_from_IDispatch(iface); | |
| TRACE("(%d, %s, 0x%x, 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 | |
| }; | |
| /****************************************************************************** | |
| * 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** stddisp) | |
| { | |
| StdDispatch *pStdDispatch; | |
| TRACE("(%p, %p, %p, %p)\n", punkOuter, pvThis, ptinfo, stddisp); | |
| if (!pvThis || !ptinfo || !stddisp) | |
| return E_INVALIDARG; | |
| pStdDispatch = CoTaskMemAlloc(sizeof(StdDispatch)); | |
| if (!pStdDispatch) | |
| return E_OUTOFMEMORY; | |
| pStdDispatch->IDispatch_iface.lpVtbl = &StdDispatch_VTable; | |
| pStdDispatch->pvThis = pvThis; | |
| pStdDispatch->pTypeInfo = ptinfo; | |
| 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(ptinfo); | |
| *stddisp = (IUnknown*)&pStdDispatch->IDispatch_iface; | |
| return S_OK; | |
| } |