1 /** 2 * Dispatch API functions 3 * 4 * Copyright 2000 Francois Jacques, Macadamian Technologies Inc. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 * 20 */ 21 22 #include "precomp.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL(ole); 25 26 /****************************************************************************** 27 * DispInvoke (OLEAUT32.30) 28 * 29 * Call an object method using the information from its type library. 30 * 31 * RETURNS 32 * Success: S_OK. 33 * Failure: Returns DISP_E_EXCEPTION and updates pexcepinfo if an exception occurs. 34 * DISP_E_BADPARAMCOUNT if the number of parameters is incorrect. 35 * DISP_E_MEMBERNOTFOUND if the method does not exist. 36 * puArgErr is updated if a parameter error (see notes) occurs. 37 * Otherwise, returns the result of calling ITypeInfo_Invoke(). 38 * 39 * NOTES 40 * Parameter errors include the following: 41 *| DISP_E_BADVARTYPE 42 *| E_INVALIDARG An argument was invalid 43 *| DISP_E_TYPEMISMATCH, 44 *| DISP_E_OVERFLOW An argument was valid but could not be coerced 45 *| DISP_E_PARAMNOTOPTIONAL A non optional parameter was not passed 46 *| DISP_E_PARAMNOTFOUND A parameter was passed that was not expected by the method 47 * This call defers to ITypeInfo_Invoke(). 48 */ 49 HRESULT WINAPI DispInvoke( 50 VOID *_this, /* [in] Object to call method on */ 51 ITypeInfo *ptinfo, /* [in] Object type info */ 52 DISPID dispidMember, /* [in] DISPID of the member (e.g. from GetIDsOfNames()) */ 53 USHORT wFlags, /* [in] Kind of method call (DISPATCH_ flags from "oaidl.h") */ 54 DISPPARAMS *pparams, /* [in] Array of method arguments */ 55 VARIANT *pvarResult, /* [out] Destination for the result of the call */ 56 EXCEPINFO *pexcepinfo, /* [out] Destination for exception information */ 57 UINT *puArgErr) /* [out] Destination for bad argument */ 58 { 59 TRACE("\n"); 60 61 return ITypeInfo_Invoke(ptinfo, _this, dispidMember, wFlags, 62 pparams, pvarResult, pexcepinfo, puArgErr); 63 } 64 65 /****************************************************************************** 66 * DispGetIDsOfNames (OLEAUT32.29) 67 * 68 * Convert a set of parameter names to DISPIDs for DispInvoke(). 69 * 70 * RETURNS 71 * Success: S_OK. 72 * Failure: An HRESULT error code. 73 * 74 * NOTES 75 * This call defers to ITypeInfo_GetIDsOfNames(). The ITypeInfo interface passed 76 * as ptinfo contains the information to map names to DISPIDs. 77 */ 78 HRESULT WINAPI DispGetIDsOfNames( 79 ITypeInfo *ptinfo, /* [in] Object's type info */ 80 OLECHAR **rgszNames, /* [in] Array of names to get DISPIDs for */ 81 UINT cNames, /* [in] Number of names in rgszNames */ 82 DISPID *rgdispid) /* [out] Destination for converted DISPIDs */ 83 { 84 return ITypeInfo_GetIDsOfNames(ptinfo, rgszNames, cNames, rgdispid); 85 } 86 87 /****************************************************************************** 88 * DispGetParam (OLEAUT32.28) 89 * 90 * Retrieve a parameter from a DISPPARAMS structure and coerce it to the 91 * specified variant type. 92 * 93 * NOTES 94 * Coercion is done using system (0) locale. 95 * 96 * RETURNS 97 * Success: S_OK. 98 * Failure: DISP_E_PARAMNOTFOUND, if position is invalid. or 99 * DISP_E_TYPEMISMATCH, if the coercion failed. puArgErr is 100 * set to the index of the argument in pdispparams. 101 */ 102 HRESULT WINAPI DispGetParam( 103 DISPPARAMS *pdispparams, /* [in] Parameter list */ 104 UINT position, /* [in] Position of parameter to coerce in pdispparams */ 105 VARTYPE vtTarg, /* [in] Type of value to coerce to */ 106 VARIANT *pvarResult, /* [out] Destination for resulting variant */ 107 UINT *puArgErr) /* [out] Destination for error code */ 108 { 109 /* position is counted backwards */ 110 UINT pos; 111 HRESULT hr; 112 113 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n", 114 position, pdispparams->cArgs, pdispparams->cNamedArgs); 115 116 if (position < pdispparams->cArgs) 117 { 118 /* positional arg? */ 119 pos = pdispparams->cArgs - position - 1; 120 } 121 else 122 { 123 /* FIXME: is this how to handle named args? */ 124 for (pos=0; pos<pdispparams->cNamedArgs; pos++) 125 if (pdispparams->rgdispidNamedArgs[pos] == position) break; 126 127 if (pos==pdispparams->cNamedArgs) 128 return DISP_E_PARAMNOTFOUND; 129 } 130 131 if (pdispparams->cArgs > 0 && !pdispparams->rgvarg) 132 { 133 hr = E_INVALIDARG; 134 goto done; 135 } 136 137 if (!pvarResult) 138 { 139 hr = E_INVALIDARG; 140 goto done; 141 } 142 143 hr = VariantChangeType(pvarResult, 144 &pdispparams->rgvarg[pos], 145 0, vtTarg); 146 147 done: 148 if (FAILED(hr)) 149 *puArgErr = pos; 150 151 return hr; 152 } 153 154 155 /****************************************************************************** 156 * IDispatch {OLEAUT32} 157 * 158 * NOTES 159 * The IDispatch interface provides a single interface to dispatch method calls, 160 * regardless of whether the object to be called is in or out of process, 161 * local or remote (e.g. being called over a network). This interface is late-bound 162 * (linked at run-time), as opposed to early-bound (linked at compile time). 163 * 164 * The interface is used by objects that wish to called by scripting 165 * languages such as VBA, in order to minimise the amount of COM and C/C++ 166 * knowledge required, or by objects that wish to live out of process from code 167 * that will call their methods. 168 * 169 * Method, property and parameter names can be localised. The details required to 170 * map names to methods and parameters are collected in a type library, usually 171 * output by an IDL compiler using the objects IDL description. This information is 172 * accessible programmatically through the ITypeLib interface (for a type library), 173 * and the ITypeInfo interface (for an object within the type library). Type information 174 * can also be created at run-time using CreateDispTypeInfo(). 175 * 176 * WRAPPERS 177 * Instead of using IDispatch directly, there are several wrapper functions available 178 * to simplify the process of calling an objects methods through IDispatch. 179 * 180 * A standard implementation of an IDispatch object is created by calling 181 * CreateStdDispatch(). Numeric Id values for the parameters and methods (DISPIDs) 182 * of an object of interest are retrieved by calling DispGetIDsOfNames(). DispGetParam() 183 * retrieves information about a particular parameter. Finally the DispInvoke() 184 * function is responsible for actually calling methods on an object. 185 * 186 * METHODS 187 */ 188 189 typedef struct 190 { 191 IDispatch IDispatch_iface; 192 void * pvThis; 193 ITypeInfo * pTypeInfo; 194 LONG ref; 195 } StdDispatch; 196 197 static inline StdDispatch *impl_from_IDispatch(IDispatch *iface) 198 { 199 return CONTAINING_RECORD(iface, StdDispatch, IDispatch_iface); 200 } 201 202 /****************************************************************************** 203 * IDispatch_QueryInterface {OLEAUT32} 204 * 205 * See IUnknown_QueryInterface. 206 */ 207 static HRESULT WINAPI StdDispatch_QueryInterface( 208 LPDISPATCH iface, 209 REFIID riid, 210 void** ppvObject) 211 { 212 StdDispatch *This = impl_from_IDispatch(iface); 213 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); 214 215 *ppvObject = NULL; 216 217 if (IsEqualIID(riid, &IID_IDispatch) || 218 IsEqualIID(riid, &IID_IUnknown)) 219 { 220 *ppvObject = iface; 221 IDispatch_AddRef(iface); 222 return S_OK; 223 } 224 return E_NOINTERFACE; 225 } 226 227 /****************************************************************************** 228 * IDispatch_AddRef {OLEAUT32} 229 * 230 * See IUnknown_AddRef. 231 */ 232 static ULONG WINAPI StdDispatch_AddRef(LPDISPATCH iface) 233 { 234 StdDispatch *This = impl_from_IDispatch(iface); 235 ULONG refCount = InterlockedIncrement(&This->ref); 236 237 TRACE("(%p)->(ref before=%u)\n",This, refCount - 1); 238 239 return refCount; 240 } 241 242 /****************************************************************************** 243 * IDispatch_Release {OLEAUT32} 244 * 245 * See IUnknown_Release. 246 */ 247 static ULONG WINAPI StdDispatch_Release(LPDISPATCH iface) 248 { 249 StdDispatch *This = impl_from_IDispatch(iface); 250 ULONG refCount = InterlockedDecrement(&This->ref); 251 252 TRACE("(%p)->(ref before=%u)\n", This, refCount + 1); 253 254 if (!refCount) 255 { 256 ITypeInfo_Release(This->pTypeInfo); 257 CoTaskMemFree(This); 258 } 259 260 return refCount; 261 } 262 263 /****************************************************************************** 264 * IDispatch_GetTypeInfoCount {OLEAUT32} 265 * 266 * Get the count of type information in an IDispatch interface. 267 * 268 * PARAMS 269 * iface [I] IDispatch interface 270 * pctinfo [O] Destination for the count 271 * 272 * RETURNS 273 * Success: S_OK. pctinfo is updated with the count. This is always 1 if 274 * the object provides type information, and 0 if it does not. 275 * Failure: E_NOTIMPL. The object does not provide type information. 276 * 277 * NOTES 278 * See IDispatch() and IDispatch_GetTypeInfo(). 279 */ 280 static HRESULT WINAPI StdDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo) 281 { 282 TRACE("(%p)\n", pctinfo); 283 *pctinfo = 1; 284 return S_OK; 285 } 286 287 /****************************************************************************** 288 * IDispatch_GetTypeInfo {OLEAUT32} 289 * 290 * Get type information from an IDispatch interface. 291 * 292 * PARAMS 293 * iface [I] IDispatch interface 294 * iTInfo [I] Index of type information. 295 * lcid [I] Locale of the type information to get 296 * ppTInfo [O] Destination for the ITypeInfo object 297 * 298 * RETURNS 299 * Success: S_OK. ppTInfo is updated with the objects type information 300 * Failure: DISP_E_BADINDEX, if iTInfo is any value other than 0. 301 * 302 * NOTES 303 * See IDispatch. 304 */ 305 static HRESULT WINAPI StdDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) 306 { 307 StdDispatch *This = impl_from_IDispatch(iface); 308 TRACE("(%d, %x, %p)\n", iTInfo, lcid, ppTInfo); 309 310 *ppTInfo = NULL; 311 if (iTInfo != 0) 312 return DISP_E_BADINDEX; 313 314 *ppTInfo = This->pTypeInfo; 315 ITypeInfo_AddRef(*ppTInfo); 316 317 return S_OK; 318 } 319 320 /****************************************************************************** 321 * IDispatch_GetIDsOfNames {OLEAUT32} 322 * 323 * Convert a methods name and an optional set of parameter names into DISPIDs 324 * for passing to IDispatch_Invoke(). 325 * 326 * PARAMS 327 * iface [I] IDispatch interface 328 * riid [I] Reserved, set to IID_NULL 329 * rgszNames [I] Name to convert 330 * cNames [I] Number of names in rgszNames 331 * lcid [I] Locale of the type information to convert from 332 * rgDispId [O] Destination for converted DISPIDs. 333 * 334 * RETURNS 335 * Success: S_OK. 336 * Failure: DISP_E_UNKNOWNNAME, if any of the names is invalid. 337 * DISP_E_UNKNOWNLCID if lcid is invalid. 338 * Otherwise, an HRESULT error code. 339 * 340 * NOTES 341 * This call defers to ITypeInfo_GetIDsOfNames(), using the ITypeInfo object 342 * contained within the IDispatch object. 343 * The first member of the names list must be a method name. The names following 344 * the method name are the parameters for that method. 345 */ 346 static HRESULT WINAPI StdDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId) 347 { 348 StdDispatch *This = impl_from_IDispatch(iface); 349 TRACE("(%s, %p, %d, 0x%x, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); 350 351 if (!IsEqualGUID(riid, &IID_NULL)) 352 { 353 FIXME(" expected riid == IID_NULL\n"); 354 return E_INVALIDARG; 355 } 356 return DispGetIDsOfNames(This->pTypeInfo, rgszNames, cNames, rgDispId); 357 } 358 359 /****************************************************************************** 360 * IDispatch_Invoke {OLEAUT32} 361 * 362 * Call an object method. 363 * 364 * PARAMS 365 * iface [I] IDispatch interface 366 * dispIdMember [I] DISPID of the method (from GetIDsOfNames()) 367 * riid [I] Reserved, set to IID_NULL 368 * lcid [I] Locale of the type information to convert parameters with 369 * wFlags, [I] Kind of method call (DISPATCH_ flags from "oaidl.h") 370 * pDispParams [I] Array of method arguments 371 * pVarResult [O] Destination for the result of the call 372 * pExcepInfo [O] Destination for exception information 373 * puArgErr [O] Destination for bad argument 374 * 375 * RETURNS 376 * Success: S_OK. 377 * Failure: See DispInvoke() for failure cases. 378 * 379 * NOTES 380 * See DispInvoke() and IDispatch(). 381 */ 382 static HRESULT WINAPI StdDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid, 383 WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, 384 EXCEPINFO * pExcepInfo, UINT * puArgErr) 385 { 386 StdDispatch *This = impl_from_IDispatch(iface); 387 TRACE("(%d, %s, 0x%x, 0x%x, %p, %p, %p, %p)\n", dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 388 389 if (!IsEqualGUID(riid, &IID_NULL)) 390 { 391 FIXME(" expected riid == IID_NULL\n"); 392 return E_INVALIDARG; 393 } 394 return DispInvoke(This->pvThis, This->pTypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 395 } 396 397 static const IDispatchVtbl StdDispatch_VTable = 398 { 399 StdDispatch_QueryInterface, 400 StdDispatch_AddRef, 401 StdDispatch_Release, 402 StdDispatch_GetTypeInfoCount, 403 StdDispatch_GetTypeInfo, 404 StdDispatch_GetIDsOfNames, 405 StdDispatch_Invoke 406 }; 407 408 /****************************************************************************** 409 * CreateStdDispatch [OLEAUT32.32] 410 * 411 * Create and return a standard IDispatch object. 412 * 413 * RETURNS 414 * Success: S_OK. ppunkStdDisp contains the new object. 415 * Failure: An HRESULT error code. 416 * 417 * NOTES 418 * Outer unknown appears to be completely ignored. 419 */ 420 HRESULT WINAPI CreateStdDispatch( 421 IUnknown* punkOuter, 422 void* pvThis, 423 ITypeInfo* ptinfo, 424 IUnknown** stddisp) 425 { 426 StdDispatch *pStdDispatch; 427 428 TRACE("(%p, %p, %p, %p)\n", punkOuter, pvThis, ptinfo, stddisp); 429 430 if (!pvThis || !ptinfo || !stddisp) 431 return E_INVALIDARG; 432 433 pStdDispatch = CoTaskMemAlloc(sizeof(StdDispatch)); 434 if (!pStdDispatch) 435 return E_OUTOFMEMORY; 436 437 pStdDispatch->IDispatch_iface.lpVtbl = &StdDispatch_VTable; 438 pStdDispatch->pvThis = pvThis; 439 pStdDispatch->pTypeInfo = ptinfo; 440 pStdDispatch->ref = 1; 441 442 /* we keep a reference to the type info so prevent it from 443 * being destroyed until we are done with it */ 444 ITypeInfo_AddRef(ptinfo); 445 *stddisp = (IUnknown*)&pStdDispatch->IDispatch_iface; 446 447 return S_OK; 448 } 449