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