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