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