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