xref: /reactos/dll/win32/msi/automation.c (revision f4be6dc3)
1 /*
2  * Implementation of OLE Automation for Microsoft Installer (msi.dll)
3  *
4  * Copyright 2007 Misha Koshelev
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 #define COBJMACROS
22 
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "msidefs.h"
30 #include "msipriv.h"
31 #include "activscp.h"
32 #include "oleauto.h"
33 #include "shlwapi.h"
34 #include "wine/debug.h"
35 
36 #include "msiserver.h"
37 #include "msiserver_dispids.h"
38 
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
40 
41 #define REG_INDEX_CLASSES_ROOT 0
42 #define REG_INDEX_DYN_DATA 6
43 
44 struct automation_object;
45 
46 struct tid_id
47 {
48     REFIID riid;
49     /* function that is called from AutomationObject::Invoke, specific to this type of object */
50     HRESULT (*fn_invoke)(struct automation_object *, DISPID, REFIID, LCID, WORD, DISPPARAMS *, VARIANT *,
51                          EXCEPINFO *, UINT *);
52     /* function that is called from AutomationObject::Release when the object is being freed
53        to free any private data structures (or NULL) */
54     void (*fn_free)(struct automation_object *);
55 };
56 
57 static HRESULT database_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
58 static HRESULT installer_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
59 static HRESULT record_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
60 static HRESULT session_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
61 static HRESULT list_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
62 static void    list_free(struct automation_object*);
63 static HRESULT summaryinfo_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
64 static HRESULT view_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
65 
66 static struct tid_id tid_ids[] =
67 {
68     { &DIID_Database,    database_invoke },
69     { &DIID_Installer,   installer_invoke },
70     { &DIID_Record,      record_invoke },
71     { &DIID_Session,     session_invoke },
72     { &DIID_StringList,  list_invoke, list_free },
73     { &DIID_SummaryInfo, summaryinfo_invoke },
74     { &DIID_View,        view_invoke }
75 };
76 
77 static ITypeLib  *typelib;
78 static ITypeInfo *typeinfos[LAST_tid];
79 
get_riid_from_tid(tid_t tid)80 static const IID *get_riid_from_tid(tid_t tid)
81 {
82     return tid_ids[tid].riid;
83 }
84 
get_typeinfo(tid_t tid,ITypeInfo ** typeinfo)85 HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo)
86 {
87     HRESULT hr;
88 
89     if (!typelib)
90     {
91         ITypeLib *lib;
92 
93         hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, LOCALE_NEUTRAL, &lib);
94         if (FAILED(hr)) {
95             hr = LoadTypeLib(L"msiserver.tlb", &lib);
96             if (FAILED(hr)) {
97                 ERR("Could not load msiserver.tlb\n");
98                 return hr;
99             }
100         }
101 
102         if (InterlockedCompareExchangePointer((void**)&typelib, lib, NULL))
103             ITypeLib_Release(lib);
104     }
105 
106     if (!typeinfos[tid])
107     {
108         ITypeInfo *ti;
109 
110         hr = ITypeLib_GetTypeInfoOfGuid(typelib, get_riid_from_tid(tid), &ti);
111         if (FAILED(hr)) {
112             ERR("Could not load ITypeInfo for %s\n", debugstr_guid(get_riid_from_tid(tid)));
113             return hr;
114         }
115 
116         if(InterlockedCompareExchangePointer((void**)(typeinfos+tid), ti, NULL))
117             ITypeInfo_Release(ti);
118     }
119 
120     *typeinfo = typeinfos[tid];
121     return S_OK;
122 }
123 
release_typelib(void)124 void release_typelib(void)
125 {
126     unsigned i;
127 
128     for (i = 0; i < ARRAY_SIZE(typeinfos); i++)
129         if (typeinfos[i])
130             ITypeInfo_Release(typeinfos[i]);
131 
132     if (typelib)
133         ITypeLib_Release(typelib);
134 }
135 
136 /*
137  * struct automation_object - "base" class for all automation objects. For each interface, we implement Invoke
138  * function called from AutomationObject::Invoke.
139  */
140 struct automation_object
141 {
142     IDispatch IDispatch_iface;
143     IProvideMultipleClassInfo IProvideMultipleClassInfo_iface;
144     LONG ref;
145 
146     /* type id for this class */
147     tid_t tid;
148 
149     /* The MSI handle of the current object */
150     MSIHANDLE msiHandle;
151 };
152 
153 struct list_object
154 {
155     struct automation_object autoobj;
156     int count;
157     VARIANT *data;
158 };
159 
160 static HRESULT create_database(MSIHANDLE, IDispatch**);
161 static HRESULT create_list_enumerator(struct list_object *, void **);
162 static HRESULT create_summaryinfo(MSIHANDLE, IDispatch**);
163 static HRESULT create_view(MSIHANDLE, IDispatch**);
164 
165 /* struct list_enumerator - IEnumVARIANT implementation for MSI automation lists */
166 struct list_enumerator
167 {
168     IEnumVARIANT IEnumVARIANT_iface;
169     LONG ref;
170 
171     /* Current position and pointer to struct automation_object that stores actual data */
172     ULONG pos;
173     struct list_object *list;
174 };
175 
176 struct session_object
177 {
178     struct automation_object autoobj;
179     IDispatch *installer;
180 };
181 
impl_from_IProvideMultipleClassInfo(IProvideMultipleClassInfo * iface)182 static inline struct automation_object *impl_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
183 {
184     return CONTAINING_RECORD(iface, struct automation_object, IProvideMultipleClassInfo_iface);
185 }
186 
impl_from_IDispatch(IDispatch * iface)187 static inline struct automation_object *impl_from_IDispatch( IDispatch *iface )
188 {
189     return CONTAINING_RECORD(iface, struct automation_object, IDispatch_iface);
190 }
191 
192 /* AutomationObject methods */
AutomationObject_QueryInterface(IDispatch * iface,REFIID riid,void ** ppvObject)193 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
194 {
195     struct automation_object *This = impl_from_IDispatch(iface);
196 
197     TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
198 
199     if (ppvObject == NULL)
200       return E_INVALIDARG;
201 
202     *ppvObject = 0;
203 
204     if (IsEqualGUID(riid, &IID_IUnknown)  ||
205         IsEqualGUID(riid, &IID_IDispatch) ||
206         IsEqualGUID(riid, get_riid_from_tid(This->tid)))
207         *ppvObject = &This->IDispatch_iface;
208     else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
209              IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
210              IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
211         *ppvObject = &This->IProvideMultipleClassInfo_iface;
212     else
213     {
214         TRACE("() : asking for unsupported interface %s\n", debugstr_guid(riid));
215         return E_NOINTERFACE;
216     }
217 
218     IDispatch_AddRef(iface);
219 
220     return S_OK;
221 }
222 
AutomationObject_AddRef(IDispatch * iface)223 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
224 {
225     struct automation_object *This = impl_from_IDispatch(iface);
226 
227     TRACE("(%p/%p)\n", iface, This);
228 
229     return InterlockedIncrement(&This->ref);
230 }
231 
AutomationObject_Release(IDispatch * iface)232 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
233 {
234     struct automation_object *This = impl_from_IDispatch(iface);
235     ULONG ref = InterlockedDecrement(&This->ref);
236 
237     TRACE("(%p/%p)\n", iface, This);
238 
239     if (!ref)
240     {
241         if (tid_ids[This->tid].fn_free) tid_ids[This->tid].fn_free(This);
242         MsiCloseHandle(This->msiHandle);
243         free(This);
244     }
245 
246     return ref;
247 }
248 
AutomationObject_GetTypeInfoCount(IDispatch * iface,UINT * pctinfo)249 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
250         IDispatch* iface,
251         UINT* pctinfo)
252 {
253     struct automation_object *This = impl_from_IDispatch(iface);
254 
255     TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
256     *pctinfo = 1;
257     return S_OK;
258 }
259 
AutomationObject_GetTypeInfo(IDispatch * iface,UINT iTInfo,LCID lcid,ITypeInfo ** ppTInfo)260 static HRESULT WINAPI AutomationObject_GetTypeInfo(
261         IDispatch* iface,
262         UINT iTInfo,
263         LCID lcid,
264         ITypeInfo** ppTInfo)
265 {
266     struct automation_object *This = impl_from_IDispatch(iface);
267     HRESULT hr;
268 
269     TRACE( "(%p/%p)->(%u, %ld, %p)\n", iface, This, iTInfo, lcid, ppTInfo );
270 
271     hr = get_typeinfo(This->tid, ppTInfo);
272     if (FAILED(hr))
273         return hr;
274 
275     ITypeInfo_AddRef(*ppTInfo);
276     return hr;
277 }
278 
AutomationObject_GetIDsOfNames(IDispatch * iface,REFIID riid,LPOLESTR * rgszNames,UINT cNames,LCID lcid,DISPID * rgDispId)279 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
280         IDispatch* iface,
281         REFIID riid,
282         LPOLESTR* rgszNames,
283         UINT cNames,
284         LCID lcid,
285         DISPID* rgDispId)
286 {
287     struct automation_object *This = impl_from_IDispatch(iface);
288     ITypeInfo *ti;
289     HRESULT hr;
290 
291     TRACE("(%p/%p)->(%s, %p, %u, %ld, %p)\n", iface, This,
292             debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
293 
294     if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
295 
296     hr = get_typeinfo(This->tid, &ti);
297     if (FAILED(hr))
298         return hr;
299 
300     hr = ITypeInfo_GetIDsOfNames(ti, rgszNames, cNames, rgDispId);
301     if (hr == DISP_E_UNKNOWNNAME)
302     {
303         UINT idx;
304         for (idx=0; idx<cNames; idx++)
305         {
306             if (rgDispId[idx] == DISPID_UNKNOWN)
307                 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(get_riid_from_tid(This->tid)));
308         }
309     }
310     return hr;
311 }
312 
313 /* Maximum number of allowed function parameters+1 */
314 #define MAX_FUNC_PARAMS 20
315 
316 /* Some error checking is done here to simplify individual object function invocation */
AutomationObject_Invoke(IDispatch * iface,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)317 static HRESULT WINAPI AutomationObject_Invoke(
318         IDispatch* iface,
319         DISPID dispIdMember,
320         REFIID riid,
321         LCID lcid,
322         WORD wFlags,
323         DISPPARAMS* pDispParams,
324         VARIANT* pVarResult,
325         EXCEPINFO* pExcepInfo,
326         UINT* puArgErr)
327 {
328     struct automation_object *This = impl_from_IDispatch(iface);
329     HRESULT hr;
330     unsigned int uArgErr;
331     VARIANT varResultDummy;
332     BSTR bstrName = NULL;
333     ITypeInfo *ti;
334 
335     TRACE("(%p/%p)->(%ld, %s, %ld, %d, %p, %p, %p, %p)\n", iface, This,
336             dispIdMember, debugstr_guid(riid), lcid, wFlags,
337             pDispParams, pVarResult, pExcepInfo, puArgErr);
338 
339     if (!IsEqualIID(riid, &IID_NULL))
340     {
341         ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
342         return DISP_E_UNKNOWNNAME;
343     }
344 
345     if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
346     {
347         ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
348         return DISP_E_PARAMNOTOPTIONAL;
349     }
350 
351     /* This simplifies our individual object invocation functions */
352     if (puArgErr == NULL) puArgErr = &uArgErr;
353     if (pVarResult == NULL) pVarResult = &varResultDummy;
354 
355     hr = get_typeinfo(This->tid, &ti);
356     if (FAILED(hr))
357         return hr;
358 
359     /* Assume return type is void unless determined otherwise */
360     VariantInit(pVarResult);
361 
362     /* If we are tracing, we want to see the name of the member we are invoking */
363     if (TRACE_ON(msi))
364     {
365         ITypeInfo_GetDocumentation(ti, dispIdMember, &bstrName, NULL, NULL, NULL);
366         TRACE("method %ld, %s\n", dispIdMember, debugstr_w(bstrName));
367     }
368 
369     hr = tid_ids[This->tid].fn_invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
370 
371     if (hr == DISP_E_MEMBERNOTFOUND) {
372         if (bstrName == NULL) ITypeInfo_GetDocumentation(ti, dispIdMember, &bstrName, NULL, NULL, NULL);
373         FIXME("method %ld, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags,
374             debugstr_guid(get_riid_from_tid(This->tid)));
375     }
376     else if (pExcepInfo &&
377              (hr == DISP_E_PARAMNOTFOUND ||
378               hr == DISP_E_EXCEPTION)) {
379         WCHAR szExceptionDescription[MAX_PATH];
380         BSTR bstrParamNames[MAX_FUNC_PARAMS];
381         unsigned namesNo, i;
382         BOOL bFirst = TRUE;
383 
384         if (FAILED(ITypeInfo_GetNames(ti, dispIdMember, bstrParamNames,
385                                       MAX_FUNC_PARAMS, &namesNo)))
386         {
387             TRACE("failed to retrieve names for dispIdMember %ld\n", dispIdMember);
388         }
389         else
390         {
391             memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
392             for (i=0; i<namesNo; i++)
393             {
394                 if (bFirst) bFirst = FALSE;
395                 else {
396                     lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], L",");
397                 }
398                 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
399                 SysFreeString(bstrParamNames[i]);
400             }
401 
402             memset(pExcepInfo, 0, sizeof(EXCEPINFO));
403             pExcepInfo->wCode = 1000;
404             pExcepInfo->bstrSource = SysAllocString(L"Msi API Error");
405             pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
406             hr = DISP_E_EXCEPTION;
407         }
408     }
409 
410     /* Make sure we free the return variant if it is our dummy variant */
411     if (pVarResult == &varResultDummy) VariantClear(pVarResult);
412 
413     /* Free function name if we retrieved it */
414     SysFreeString(bstrName);
415 
416     TRACE("returning %#lx, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
417 
418     return hr;
419 }
420 
421 static const struct IDispatchVtbl AutomationObjectVtbl =
422 {
423     AutomationObject_QueryInterface,
424     AutomationObject_AddRef,
425     AutomationObject_Release,
426     AutomationObject_GetTypeInfoCount,
427     AutomationObject_GetTypeInfo,
428     AutomationObject_GetIDsOfNames,
429     AutomationObject_Invoke
430 };
431 
432 /*
433  * IProvideMultipleClassInfo methods
434  */
435 
ProvideMultipleClassInfo_QueryInterface(IProvideMultipleClassInfo * iface,REFIID riid,VOID ** ppvoid)436 static HRESULT WINAPI ProvideMultipleClassInfo_QueryInterface(
437   IProvideMultipleClassInfo* iface,
438   REFIID     riid,
439   VOID**     ppvoid)
440 {
441     struct automation_object *This = impl_from_IProvideMultipleClassInfo(iface);
442     return IDispatch_QueryInterface(&This->IDispatch_iface, riid, ppvoid);
443 }
444 
ProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo * iface)445 static ULONG WINAPI ProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
446 {
447     struct automation_object *This = impl_from_IProvideMultipleClassInfo(iface);
448     return IDispatch_AddRef(&This->IDispatch_iface);
449 }
450 
ProvideMultipleClassInfo_Release(IProvideMultipleClassInfo * iface)451 static ULONG WINAPI ProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
452 {
453     struct automation_object *This = impl_from_IProvideMultipleClassInfo(iface);
454     return IDispatch_Release(&This->IDispatch_iface);
455 }
456 
ProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo * iface,ITypeInfo ** ppTI)457 static HRESULT WINAPI ProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
458 {
459     struct automation_object *This = impl_from_IProvideMultipleClassInfo(iface);
460     HRESULT hr;
461 
462     TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
463 
464     hr = get_typeinfo(This->tid, ppTI);
465     if (SUCCEEDED(hr))
466         ITypeInfo_AddRef(*ppTI);
467 
468     return hr;
469 }
470 
ProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo * iface,DWORD dwGuidKind,GUID * pGUID)471 static HRESULT WINAPI ProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
472 {
473     struct automation_object *This = impl_from_IProvideMultipleClassInfo(iface);
474     TRACE("(%p/%p)->(%lu, %s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
475 
476     if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
477         return E_INVALIDARG;
478     else {
479         *pGUID = *get_riid_from_tid(This->tid);
480         return S_OK;
481     }
482 }
483 
ProvideMultipleClassInfo_GetMultiTypeInfoCount(IProvideMultipleClassInfo * iface,ULONG * pcti)484 static HRESULT WINAPI ProvideMultipleClassInfo_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
485 {
486     struct automation_object *This = impl_from_IProvideMultipleClassInfo(iface);
487 
488     TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
489     *pcti = 1;
490     return S_OK;
491 }
492 
ProvideMultipleClassInfo_GetInfoOfIndex(IProvideMultipleClassInfo * iface,ULONG iti,DWORD dwFlags,ITypeInfo ** ti,DWORD * pdwTIFlags,ULONG * pcdispidReserved,IID * piidPrimary,IID * piidSource)493 static HRESULT WINAPI ProvideMultipleClassInfo_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
494         ULONG iti,
495         DWORD dwFlags,
496         ITypeInfo** ti,
497         DWORD* pdwTIFlags,
498         ULONG* pcdispidReserved,
499         IID* piidPrimary,
500         IID* piidSource)
501 {
502     struct automation_object *This = impl_from_IProvideMultipleClassInfo(iface);
503 
504     TRACE("(%p/%p)->(%lu, %#lx, %p, %p, %p, %p, %p)\n", iface, This, iti, dwFlags, ti, pdwTIFlags, pcdispidReserved,
505           piidPrimary, piidSource);
506 
507     if (iti != 0)
508         return E_INVALIDARG;
509 
510     if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
511     {
512         HRESULT hr = get_typeinfo(This->tid, ti);
513         if (FAILED(hr))
514             return hr;
515 
516         ITypeInfo_AddRef(*ti);
517     }
518 
519     if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
520     {
521         *pdwTIFlags = 0;
522         *pcdispidReserved = 0;
523     }
524 
525     if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY)
526         *piidPrimary = *get_riid_from_tid(This->tid);
527 
528     if (dwFlags & MULTICLASSINFO_GETIIDSOURCE)
529         *piidSource = *get_riid_from_tid(This->tid);
530 
531     return S_OK;
532 }
533 
534 static const IProvideMultipleClassInfoVtbl ProvideMultipleClassInfoVtbl =
535 {
536     ProvideMultipleClassInfo_QueryInterface,
537     ProvideMultipleClassInfo_AddRef,
538     ProvideMultipleClassInfo_Release,
539     ProvideMultipleClassInfo_GetClassInfo,
540     ProvideMultipleClassInfo_GetGUID,
541     ProvideMultipleClassInfo_GetMultiTypeInfoCount,
542     ProvideMultipleClassInfo_GetInfoOfIndex
543 };
544 
init_automation_object(struct automation_object * This,MSIHANDLE msiHandle,tid_t tid)545 static void init_automation_object(struct automation_object *This, MSIHANDLE msiHandle, tid_t tid)
546 {
547     TRACE("%p, %lu, %s\n", This, msiHandle, debugstr_guid(get_riid_from_tid(tid)));
548 
549     This->IDispatch_iface.lpVtbl = &AutomationObjectVtbl;
550     This->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl;
551     This->ref = 1;
552     This->msiHandle = msiHandle;
553     This->tid = tid;
554 }
555 
556 /*
557  * ListEnumerator methods
558  */
559 
impl_from_IEnumVARIANT(IEnumVARIANT * iface)560 static inline struct list_enumerator *impl_from_IEnumVARIANT(IEnumVARIANT* iface)
561 {
562     return CONTAINING_RECORD(iface, struct list_enumerator, IEnumVARIANT_iface);
563 }
564 
ListEnumerator_QueryInterface(IEnumVARIANT * iface,REFIID riid,void ** ppvObject)565 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid,
566         void** ppvObject)
567 {
568     struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
569 
570     TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
571 
572     if (ppvObject == NULL)
573       return E_INVALIDARG;
574 
575     *ppvObject = 0;
576 
577     if (IsEqualGUID(riid, &IID_IUnknown) ||
578         IsEqualGUID(riid, &IID_IEnumVARIANT))
579     {
580         *ppvObject = &This->IEnumVARIANT_iface;
581     }
582     else
583     {
584         TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
585         return E_NOINTERFACE;
586     }
587 
588     IEnumVARIANT_AddRef(iface);
589     return S_OK;
590 }
591 
ListEnumerator_AddRef(IEnumVARIANT * iface)592 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
593 {
594     struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
595 
596     TRACE("(%p/%p)\n", iface, This);
597 
598     return InterlockedIncrement(&This->ref);
599 }
600 
ListEnumerator_Release(IEnumVARIANT * iface)601 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
602 {
603     struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
604     ULONG ref = InterlockedDecrement(&This->ref);
605 
606     TRACE("(%p/%p)\n", iface, This);
607 
608     if (!ref)
609     {
610         if (This->list) IDispatch_Release(&This->list->autoobj.IDispatch_iface);
611         free(This);
612     }
613 
614     return ref;
615 }
616 
ListEnumerator_Next(IEnumVARIANT * iface,ULONG celt,VARIANT * rgVar,ULONG * fetched)617 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar,
618         ULONG* fetched)
619 {
620     struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
621     ULONG i, local;
622 
623     TRACE("%p, %lu, %p, %p\n", iface, celt, rgVar, fetched);
624 
625     if (fetched) *fetched = 0;
626 
627     if (!rgVar)
628         return S_FALSE;
629 
630     for (local = 0; local < celt; local++)
631         VariantInit(&rgVar[local]);
632 
633     for (i = This->pos, local = 0; i < This->list->count && local < celt; i++, local++)
634         VariantCopy(&rgVar[local], &This->list->data[i]);
635 
636     if (fetched) *fetched = local;
637     This->pos = i;
638 
639     return (local < celt) ? S_FALSE : S_OK;
640 }
641 
ListEnumerator_Skip(IEnumVARIANT * iface,ULONG celt)642 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
643 {
644     struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
645 
646     TRACE("%p, %lu\n", iface, celt);
647 
648     This->pos += celt;
649     if (This->pos >= This->list->count)
650     {
651         This->pos = This->list->count;
652         return S_FALSE;
653     }
654 
655     return S_OK;
656 }
657 
ListEnumerator_Reset(IEnumVARIANT * iface)658 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
659 {
660     struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
661 
662     TRACE("(%p)\n", iface);
663 
664     This->pos = 0;
665     return S_OK;
666 }
667 
ListEnumerator_Clone(IEnumVARIANT * iface,IEnumVARIANT ** ppEnum)668 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
669 {
670     struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
671     HRESULT hr;
672 
673     TRACE("(%p,%p)\n", iface, ppEnum);
674 
675     if (ppEnum == NULL)
676         return S_FALSE;
677 
678     *ppEnum = NULL;
679     hr = create_list_enumerator(This->list, (LPVOID *)ppEnum);
680     if (FAILED(hr))
681     {
682         if (*ppEnum) IEnumVARIANT_Release(*ppEnum);
683         return hr;
684     }
685 
686     return S_OK;
687 }
688 
689 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
690 {
691     ListEnumerator_QueryInterface,
692     ListEnumerator_AddRef,
693     ListEnumerator_Release,
694     ListEnumerator_Next,
695     ListEnumerator_Skip,
696     ListEnumerator_Reset,
697     ListEnumerator_Clone
698 };
699 
700 /* Create a list enumerator, placing the result in the pointer ppObj.  */
create_list_enumerator(struct list_object * list,void ** ppObj)701 static HRESULT create_list_enumerator(struct list_object *list, void **ppObj)
702 {
703     struct list_enumerator *object;
704 
705     TRACE("(%p, %p)\n", list, ppObj);
706 
707     object = malloc(sizeof(*object));
708 
709     /* Set all the VTable references */
710     object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
711     object->ref = 1;
712 
713     /* Store data that was passed */
714     object->pos = 0;
715     object->list = list;
716     if (list) IDispatch_AddRef(&list->autoobj.IDispatch_iface);
717 
718     *ppObj = object;
719     return S_OK;
720 }
721 
722 /*
723  * Individual Object Invocation Functions
724  */
725 
726 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
727    This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
728    using DispGetParam/VariantChangeType. */
DispGetParam_CopyOnly(DISPPARAMS * pdispparams,UINT * position,VARIANT * pvarResult)729 static HRESULT DispGetParam_CopyOnly(
730         DISPPARAMS *pdispparams, /* [in] Parameter list */
731         UINT        *position,    /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
732         VARIANT    *pvarResult)  /* [out] Destination for resulting variant */
733 {
734     /* position is counted backwards */
735     UINT pos;
736 
737     TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
738           *position, pdispparams->cArgs, pdispparams->cNamedArgs);
739     if (*position < pdispparams->cArgs) {
740       /* positional arg? */
741       pos = pdispparams->cArgs - *position - 1;
742     } else {
743       /* FIXME: is this how to handle named args? */
744       for (pos=0; pos<pdispparams->cNamedArgs; pos++)
745         if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
746 
747       if (pos==pdispparams->cNamedArgs)
748         return DISP_E_PARAMNOTFOUND;
749     }
750     *position = pos;
751     return VariantCopyInd(pvarResult,
752                         &pdispparams->rgvarg[pos]);
753 }
754 
summaryinfo_invoke(struct automation_object * This,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)755 static HRESULT summaryinfo_invoke(
756         struct automation_object *This,
757         DISPID dispIdMember,
758         REFIID riid,
759         LCID lcid,
760         WORD wFlags,
761         DISPPARAMS* pDispParams,
762         VARIANT* pVarResult,
763         EXCEPINFO* pExcepInfo,
764         UINT* puArgErr)
765 {
766     UINT ret;
767     VARIANTARG varg0, varg1;
768     FILETIME ft, ftlocal;
769     SYSTEMTIME st;
770     HRESULT hr;
771 
772     VariantInit(&varg0);
773     VariantInit(&varg1);
774 
775     switch (dispIdMember)
776     {
777         case DISPID_SUMMARYINFO_PROPERTY:
778             if (wFlags & DISPATCH_PROPERTYGET)
779             {
780                 UINT type;
781                 INT value;
782                 DWORD size = 0;
783                 DATE date;
784                 LPWSTR str;
785 
786                 static WCHAR szEmpty[] = L"";
787 
788                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
789                 if (FAILED(hr)) return hr;
790                 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
791                                                  &ft, szEmpty, &size);
792                 if (ret != ERROR_SUCCESS &&
793                     ret != ERROR_MORE_DATA)
794                 {
795                     ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
796                     return DISP_E_EXCEPTION;
797                 }
798 
799                 switch (type)
800                 {
801                     case VT_EMPTY:
802                         break;
803 
804                     case VT_I2:
805                     case VT_I4:
806                         V_VT(pVarResult) = VT_I4;
807                         V_I4(pVarResult) = value;
808                         break;
809 
810                     case VT_LPSTR:
811                         if (!(str = malloc(++size * sizeof(WCHAR))))
812                             ERR("Out of memory\n");
813                         else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
814                                                                    NULL, str, &size)) != ERROR_SUCCESS)
815                             ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
816                         else
817                         {
818                             V_VT(pVarResult) = VT_BSTR;
819                             V_BSTR(pVarResult) = SysAllocString(str);
820                         }
821                         free(str);
822                         break;
823 
824                     case VT_FILETIME:
825                         FileTimeToLocalFileTime(&ft, &ftlocal);
826                         FileTimeToSystemTime(&ftlocal, &st);
827                         SystemTimeToVariantTime(&st, &date);
828 
829                         V_VT(pVarResult) = VT_DATE;
830                         V_DATE(pVarResult) = date;
831                         break;
832 
833                     default:
834                         ERR("Unhandled variant type %d\n", type);
835                 }
836             }
837             else if (wFlags & DISPATCH_PROPERTYPUT)
838             {
839                 UINT posValue = DISPID_PROPERTYPUT;
840 
841                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
842                 if (FAILED(hr)) return hr;
843                 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
844                 if (FAILED(hr))
845                 {
846                     *puArgErr = posValue;
847                     return hr;
848                 }
849 
850                 switch (V_VT(&varg1))
851                 {
852                     case VT_I2:
853                     case VT_I4:
854                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
855                         break;
856 
857                     case VT_DATE:
858                         VariantTimeToSystemTime(V_DATE(&varg1), &st);
859                         SystemTimeToFileTime(&st, &ftlocal);
860                         LocalFileTimeToFileTime(&ftlocal, &ft);
861                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
862                         break;
863 
864                     case VT_BSTR:
865                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
866                         break;
867 
868                     default:
869                         FIXME("Unhandled variant type %d\n", V_VT(&varg1));
870                         VariantClear(&varg1);
871                         return DISP_E_EXCEPTION;
872                 }
873 
874                 if (ret != ERROR_SUCCESS)
875                 {
876                     ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
877                     return DISP_E_EXCEPTION;
878                 }
879             }
880             else return DISP_E_MEMBERNOTFOUND;
881             break;
882 
883         case DISPID_SUMMARYINFO_PROPERTYCOUNT:
884             if (wFlags & DISPATCH_PROPERTYGET) {
885                 UINT count;
886                 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
887                     ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
888                 else
889                 {
890                     V_VT(pVarResult) = VT_I4;
891                     V_I4(pVarResult) = count;
892                 }
893             }
894             else return DISP_E_MEMBERNOTFOUND;
895             break;
896 
897         default:
898             return DISP_E_MEMBERNOTFOUND;
899     }
900 
901     VariantClear(&varg1);
902     VariantClear(&varg0);
903 
904     return S_OK;
905 }
906 
record_invoke(struct automation_object * This,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)907 static HRESULT record_invoke(
908         struct automation_object *This,
909         DISPID dispIdMember,
910         REFIID riid,
911         LCID lcid,
912         WORD wFlags,
913         DISPPARAMS* pDispParams,
914         VARIANT* pVarResult,
915         EXCEPINFO* pExcepInfo,
916         UINT* puArgErr)
917 {
918     WCHAR *szString;
919     DWORD dwLen = 0;
920     UINT ret;
921     VARIANTARG varg0, varg1;
922     HRESULT hr;
923 
924     VariantInit(&varg0);
925     VariantInit(&varg1);
926 
927     switch (dispIdMember)
928     {
929         case DISPID_RECORD_FIELDCOUNT:
930             if (wFlags & DISPATCH_PROPERTYGET) {
931                 V_VT(pVarResult) = VT_I4;
932                 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
933             }
934             else return DISP_E_MEMBERNOTFOUND;
935             break;
936 
937         case DISPID_RECORD_STRINGDATA:
938             if (wFlags & DISPATCH_PROPERTYGET) {
939                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
940                 if (FAILED(hr)) return hr;
941                 V_VT(pVarResult) = VT_BSTR;
942                 V_BSTR(pVarResult) = NULL;
943                 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
944                 {
945                     if (!(szString = malloc((++dwLen) * sizeof(WCHAR))))
946                         ERR("Out of memory\n");
947                     else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
948                         V_BSTR(pVarResult) = SysAllocString(szString);
949                     free(szString);
950                 }
951                 if (ret != ERROR_SUCCESS)
952                     ERR("MsiRecordGetString returned %d\n", ret);
953             } else if (wFlags & DISPATCH_PROPERTYPUT) {
954                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
955                 if (FAILED(hr)) return hr;
956                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
957                 if (FAILED(hr)) return hr;
958                 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
959                 {
960                     VariantClear(&varg1);
961                     ERR("MsiRecordSetString returned %d\n", ret);
962                     return DISP_E_EXCEPTION;
963                 }
964             }
965             else return DISP_E_MEMBERNOTFOUND;
966             break;
967 
968         case DISPID_RECORD_INTEGERDATA:
969             if (wFlags & DISPATCH_PROPERTYGET) {
970                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
971                 if (FAILED(hr)) return hr;
972                 V_VT(pVarResult) = VT_I4;
973                 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
974             } else if (wFlags & DISPATCH_PROPERTYPUT) {
975                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
976                 if (FAILED(hr)) return hr;
977                 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
978                 if (FAILED(hr)) return hr;
979                 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
980                 {
981                     ERR("MsiRecordSetInteger returned %d\n", ret);
982                     return DISP_E_EXCEPTION;
983                 }
984             }
985             else return DISP_E_MEMBERNOTFOUND;
986             break;
987 
988          default:
989             return DISP_E_MEMBERNOTFOUND;
990     }
991 
992     VariantClear(&varg1);
993     VariantClear(&varg0);
994 
995     return S_OK;
996 }
997 
create_record(MSIHANDLE msiHandle,IDispatch ** disp)998 static HRESULT create_record(MSIHANDLE msiHandle, IDispatch **disp)
999 {
1000     struct automation_object *record;
1001 
1002     record = malloc(sizeof(*record));
1003     if (!record) return E_OUTOFMEMORY;
1004 
1005     init_automation_object(record, msiHandle, Record_tid);
1006 
1007     *disp = &record->IDispatch_iface;
1008 
1009     return S_OK;
1010 }
1011 
list_invoke(struct automation_object * This,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1012 static HRESULT list_invoke(
1013         struct automation_object *This,
1014         DISPID dispIdMember,
1015         REFIID riid,
1016         LCID lcid,
1017         WORD wFlags,
1018         DISPPARAMS* pDispParams,
1019         VARIANT* pVarResult,
1020         EXCEPINFO* pExcepInfo,
1021         UINT* puArgErr)
1022 {
1023     struct list_object *list = CONTAINING_RECORD(This, struct list_object, autoobj);
1024     IUnknown *pUnk = NULL;
1025     HRESULT hr;
1026 
1027     switch (dispIdMember)
1028     {
1029          case DISPID_LIST__NEWENUM:
1030              if (wFlags & DISPATCH_METHOD) {
1031                  V_VT(pVarResult) = VT_UNKNOWN;
1032                  if (SUCCEEDED(hr = create_list_enumerator(list, (LPVOID *)&pUnk)))
1033                      V_UNKNOWN(pVarResult) = pUnk;
1034                  else
1035                      ERR("failed to create IEnumVARIANT object, hresult %#lx\n", hr);
1036              }
1037              else return DISP_E_MEMBERNOTFOUND;
1038              break;
1039 
1040          case DISPID_LIST_ITEM:
1041              if (wFlags & DISPATCH_PROPERTYGET) {
1042                 VARIANTARG index;
1043 
1044                 VariantInit(&index);
1045                 hr = DispGetParam(pDispParams, 0, VT_I4, &index, puArgErr);
1046                 if (FAILED(hr)) return hr;
1047                 if (V_I4(&index) < 0 || V_I4(&index) >= list->count)
1048                     return DISP_E_BADINDEX;
1049                 VariantCopy(pVarResult, &list->data[V_I4(&index)]);
1050             }
1051             else return DISP_E_MEMBERNOTFOUND;
1052             break;
1053 
1054          case DISPID_LIST_COUNT:
1055             if (wFlags & DISPATCH_PROPERTYGET) {
1056                 V_VT(pVarResult) = VT_I4;
1057                 V_I4(pVarResult) = list->count;
1058             }
1059             else return DISP_E_MEMBERNOTFOUND;
1060             break;
1061 
1062          default:
1063             return DISP_E_MEMBERNOTFOUND;
1064     }
1065 
1066     return S_OK;
1067 }
1068 
list_free(struct automation_object * This)1069 static void list_free(struct automation_object *This)
1070 {
1071     struct list_object *list = CONTAINING_RECORD(This, struct list_object, autoobj);
1072     int i;
1073 
1074     for (i = 0; i < list->count; i++)
1075         VariantClear(&list->data[i]);
1076     free(list->data);
1077 }
1078 
get_products_count(const WCHAR * product,int * len)1079 static HRESULT get_products_count(const WCHAR *product, int *len)
1080 {
1081     int i = 0;
1082 
1083     while (1)
1084     {
1085         WCHAR dataW[GUID_SIZE];
1086         UINT ret;
1087 
1088         /* all or related only */
1089         if (product)
1090             ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1091         else
1092             ret = MsiEnumProductsW(i, dataW);
1093 
1094         if (ret == ERROR_NO_MORE_ITEMS) break;
1095 
1096         if (ret != ERROR_SUCCESS)
1097             return DISP_E_EXCEPTION;
1098 
1099         i++;
1100     }
1101 
1102     *len = i;
1103 
1104     return S_OK;
1105 }
1106 
create_list(const WCHAR * product,IDispatch ** dispatch)1107 static HRESULT create_list(const WCHAR *product, IDispatch **dispatch)
1108 {
1109     struct list_object *list;
1110     HRESULT hr;
1111     int i;
1112 
1113     list = calloc(1, sizeof(*list));
1114     if (!list) return E_OUTOFMEMORY;
1115 
1116     init_automation_object(&list->autoobj, 0, StringList_tid);
1117 
1118     *dispatch = &list->autoobj.IDispatch_iface;
1119 
1120     hr = get_products_count(product, &list->count);
1121     if (hr != S_OK)
1122     {
1123         IDispatch_Release(*dispatch);
1124         return hr;
1125     }
1126 
1127     list->data = malloc(list->count * sizeof(VARIANT));
1128     if (!list->data)
1129     {
1130         IDispatch_Release(*dispatch);
1131         return E_OUTOFMEMORY;
1132     }
1133 
1134     for (i = 0; i < list->count; i++)
1135     {
1136         WCHAR dataW[GUID_SIZE];
1137         UINT ret;
1138 
1139         /* all or related only */
1140         if (product)
1141             ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1142         else
1143             ret = MsiEnumProductsW(i, dataW);
1144 
1145         if (ret == ERROR_NO_MORE_ITEMS) break;
1146 
1147         V_VT(&list->data[i]) = VT_BSTR;
1148         V_BSTR(&list->data[i]) = SysAllocString(dataW);
1149     }
1150 
1151     return S_OK;
1152 }
1153 
view_invoke(struct automation_object * This,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1154 static HRESULT view_invoke(
1155         struct automation_object *This,
1156         DISPID dispIdMember,
1157         REFIID riid,
1158         LCID lcid,
1159         WORD wFlags,
1160         DISPPARAMS* pDispParams,
1161         VARIANT* pVarResult,
1162         EXCEPINFO* pExcepInfo,
1163         UINT* puArgErr)
1164 {
1165     MSIHANDLE msiHandle;
1166     UINT ret;
1167     VARIANTARG varg0, varg1;
1168     HRESULT hr;
1169 
1170     VariantInit(&varg0);
1171     VariantInit(&varg1);
1172 
1173     switch (dispIdMember)
1174     {
1175         case DISPID_VIEW_EXECUTE:
1176             if (wFlags & DISPATCH_METHOD)
1177             {
1178                 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1179                 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1180                     MsiViewExecute(This->msiHandle, ((struct automation_object *)V_DISPATCH(&varg0))->msiHandle);
1181                 else
1182                     MsiViewExecute(This->msiHandle, 0);
1183             }
1184             else return DISP_E_MEMBERNOTFOUND;
1185             break;
1186 
1187         case DISPID_VIEW_FETCH:
1188             if (wFlags & DISPATCH_METHOD)
1189             {
1190                 V_VT(pVarResult) = VT_DISPATCH;
1191                 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1192                 {
1193                     if (FAILED(hr = create_record(msiHandle, &V_DISPATCH(pVarResult))))
1194                         ERR("failed to create Record object, hresult %#lx\n", hr);
1195                 }
1196                 else if (ret == ERROR_NO_MORE_ITEMS)
1197                     V_DISPATCH(pVarResult) = NULL;
1198                 else
1199                 {
1200                     ERR("MsiViewFetch returned %d\n", ret);
1201                     return DISP_E_EXCEPTION;
1202                 }
1203             }
1204             else return DISP_E_MEMBERNOTFOUND;
1205             break;
1206 
1207         case DISPID_VIEW_MODIFY:
1208             if (wFlags & DISPATCH_METHOD)
1209             {
1210                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1211                 if (FAILED(hr)) return hr;
1212                 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1213                 if (FAILED(hr)) return hr;
1214                 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1215                 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0),
1216                                          ((struct automation_object *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1217                 {
1218                     VariantClear(&varg1);
1219                     ERR("MsiViewModify returned %d\n", ret);
1220                     return DISP_E_EXCEPTION;
1221                 }
1222             }
1223             else return DISP_E_MEMBERNOTFOUND;
1224             break;
1225 
1226         case DISPID_VIEW_CLOSE:
1227             if (wFlags & DISPATCH_METHOD)
1228             {
1229                 MsiViewClose(This->msiHandle);
1230             }
1231             else return DISP_E_MEMBERNOTFOUND;
1232             break;
1233 
1234          default:
1235             return DISP_E_MEMBERNOTFOUND;
1236     }
1237 
1238     VariantClear(&varg1);
1239     VariantClear(&varg0);
1240 
1241     return S_OK;
1242 }
1243 
DatabaseImpl_LastErrorRecord(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1244 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
1245                                             DISPPARAMS* pDispParams,
1246                                             VARIANT* pVarResult,
1247                                             EXCEPINFO* pExcepInfo,
1248                                             UINT* puArgErr)
1249 {
1250     if (!(wFlags & DISPATCH_METHOD))
1251         return DISP_E_MEMBERNOTFOUND;
1252 
1253     FIXME("\n");
1254 
1255     VariantInit(pVarResult);
1256     return S_OK;
1257 }
1258 
database_invoke(struct automation_object * This,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1259 HRESULT database_invoke(
1260         struct automation_object *This,
1261         DISPID dispIdMember,
1262         REFIID riid,
1263         LCID lcid,
1264         WORD wFlags,
1265         DISPPARAMS* pDispParams,
1266         VARIANT* pVarResult,
1267         EXCEPINFO* pExcepInfo,
1268         UINT* puArgErr)
1269 {
1270     IDispatch *dispatch = NULL;
1271     MSIHANDLE msiHandle;
1272     UINT ret;
1273     VARIANTARG varg0, varg1;
1274     HRESULT hr;
1275 
1276     VariantInit(&varg0);
1277     VariantInit(&varg1);
1278 
1279     switch (dispIdMember)
1280     {
1281         case DISPID_DATABASE_SUMMARYINFORMATION:
1282             if (wFlags & DISPATCH_PROPERTYGET)
1283             {
1284                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1285                 if (FAILED(hr))
1286                     V_I4(&varg0) = 0;
1287 
1288                 V_VT(pVarResult) = VT_DISPATCH;
1289                 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1290                 {
1291                     hr = create_summaryinfo(msiHandle, &dispatch);
1292                     if (SUCCEEDED(hr))
1293                         V_DISPATCH(pVarResult) = dispatch;
1294                     else
1295                         ERR("failed to create SummaryInfo object: %#lx\n", hr);
1296                 }
1297                 else
1298                 {
1299                     ERR("MsiGetSummaryInformation returned %d\n", ret);
1300                     return DISP_E_EXCEPTION;
1301                 }
1302             }
1303             else return DISP_E_MEMBERNOTFOUND;
1304             break;
1305 
1306         case DISPID_DATABASE_OPENVIEW:
1307             if (wFlags & DISPATCH_METHOD)
1308             {
1309                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1310                 if (FAILED(hr)) return hr;
1311                 V_VT(pVarResult) = VT_DISPATCH;
1312                 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1313                 {
1314                     if (SUCCEEDED(hr = create_view(msiHandle, &dispatch)))
1315                         V_DISPATCH(pVarResult) = dispatch;
1316                     else
1317                         ERR("failed to create View object, hresult %#lx\n", hr);
1318                 }
1319                 else
1320                 {
1321                     VariantClear(&varg0);
1322                     ERR("MsiDatabaseOpenView returned %d\n", ret);
1323                     return DISP_E_EXCEPTION;
1324                 }
1325             }
1326             else return DISP_E_MEMBERNOTFOUND;
1327             break;
1328 
1329         case DISPID_INSTALLER_LASTERRORRECORD:
1330             return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
1331                                                 pVarResult, pExcepInfo,
1332                                                 puArgErr);
1333 
1334          default:
1335             return DISP_E_MEMBERNOTFOUND;
1336     }
1337 
1338     VariantClear(&varg1);
1339     VariantClear(&varg0);
1340 
1341     return S_OK;
1342 }
1343 
session_invoke(struct automation_object * This,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1344 static HRESULT session_invoke(
1345         struct automation_object *This,
1346         DISPID dispIdMember,
1347         REFIID riid,
1348         LCID lcid,
1349         WORD wFlags,
1350         DISPPARAMS* pDispParams,
1351         VARIANT* pVarResult,
1352         EXCEPINFO* pExcepInfo,
1353         UINT* puArgErr)
1354 {
1355     struct session_object *session = CONTAINING_RECORD(This, struct session_object, autoobj);
1356     WCHAR *szString;
1357     DWORD dwLen = 0;
1358     MSIHANDLE msiHandle;
1359     LANGID langId;
1360     UINT ret;
1361     INSTALLSTATE iInstalled, iAction;
1362     VARIANTARG varg0, varg1;
1363     HRESULT hr;
1364 
1365     VariantInit(&varg0);
1366     VariantInit(&varg1);
1367 
1368     switch (dispIdMember)
1369     {
1370         case DISPID_SESSION_INSTALLER:
1371             if (wFlags & DISPATCH_PROPERTYGET) {
1372                 V_VT(pVarResult) = VT_DISPATCH;
1373                 IDispatch_AddRef(session->installer);
1374                 V_DISPATCH(pVarResult) = session->installer;
1375             }
1376             else return DISP_E_MEMBERNOTFOUND;
1377             break;
1378 
1379         case DISPID_SESSION_PROPERTY:
1380             if (wFlags & DISPATCH_PROPERTYGET) {
1381                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1382                 if (FAILED(hr)) return hr;
1383                 V_VT(pVarResult) = VT_BSTR;
1384                 V_BSTR(pVarResult) = NULL;
1385                 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1386                 {
1387                     if (!(szString = malloc((++dwLen) * sizeof(WCHAR))))
1388                         ERR("Out of memory\n");
1389                     else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1390                         V_BSTR(pVarResult) = SysAllocString(szString);
1391                     free(szString);
1392                 }
1393                 if (ret != ERROR_SUCCESS)
1394                     ERR("MsiGetProperty returned %d\n", ret);
1395             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1396                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1397                 if (FAILED(hr)) return hr;
1398                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1399                 if (FAILED(hr)) {
1400                     VariantClear(&varg0);
1401                     return hr;
1402                 }
1403                 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1404                 {
1405                     VariantClear(&varg0);
1406                     VariantClear(&varg1);
1407                     ERR("MsiSetProperty returned %d\n", ret);
1408                     return DISP_E_EXCEPTION;
1409                 }
1410             }
1411             else return DISP_E_MEMBERNOTFOUND;
1412             break;
1413 
1414         case DISPID_SESSION_LANGUAGE:
1415             if (wFlags & DISPATCH_PROPERTYGET) {
1416                 langId = MsiGetLanguage(This->msiHandle);
1417                 V_VT(pVarResult) = VT_I4;
1418                 V_I4(pVarResult) = langId;
1419             }
1420             else return DISP_E_MEMBERNOTFOUND;
1421             break;
1422 
1423         case DISPID_SESSION_MODE:
1424             if (wFlags & DISPATCH_PROPERTYGET) {
1425                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1426                 if (FAILED(hr)) return hr;
1427                 V_VT(pVarResult) = VT_BOOL;
1428                 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0)) ? VARIANT_TRUE : VARIANT_FALSE;
1429             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1430                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1431                 if (FAILED(hr)) return hr;
1432                 hr = DispGetParam(pDispParams, 1, VT_BOOL, &varg1, puArgErr);
1433                 if (FAILED(hr)) return hr;
1434                 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1435                 {
1436                     ERR("MsiSetMode returned %d\n", ret);
1437                     return DISP_E_EXCEPTION;
1438                 }
1439             }
1440             else return DISP_E_MEMBERNOTFOUND;
1441             break;
1442 
1443         case DISPID_SESSION_DATABASE:
1444             if (wFlags & DISPATCH_PROPERTYGET) {
1445                 V_VT(pVarResult) = VT_DISPATCH;
1446                 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1447                 {
1448                     IDispatch *dispatch;
1449 
1450                     if (SUCCEEDED(hr = create_database(msiHandle, &dispatch)))
1451                         V_DISPATCH(pVarResult) = dispatch;
1452                     else
1453                         ERR("failed to create Database object, hresult %#lx\n", hr);
1454                 }
1455                 else
1456                 {
1457                     ERR("MsiGetActiveDatabase failed\n");
1458                     return DISP_E_EXCEPTION;
1459                 }
1460             }
1461             else return DISP_E_MEMBERNOTFOUND;
1462             break;
1463 
1464         case DISPID_SESSION_DOACTION:
1465             if (wFlags & DISPATCH_METHOD) {
1466                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1467                 if (FAILED(hr)) return hr;
1468                 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1469                 V_VT(pVarResult) = VT_I4;
1470                 switch (ret)
1471                 {
1472                     case ERROR_FUNCTION_NOT_CALLED:
1473                         V_I4(pVarResult) = msiDoActionStatusNoAction;
1474                         break;
1475                     case ERROR_SUCCESS:
1476                         V_I4(pVarResult) = msiDoActionStatusSuccess;
1477                         break;
1478                     case ERROR_INSTALL_USEREXIT:
1479                         V_I4(pVarResult) = msiDoActionStatusUserExit;
1480                         break;
1481                     case ERROR_INSTALL_FAILURE:
1482                         V_I4(pVarResult) = msiDoActionStatusFailure;
1483                         break;
1484                     case ERROR_INSTALL_SUSPEND:
1485                         V_I4(pVarResult) = msiDoActionStatusSuspend;
1486                         break;
1487                     case ERROR_MORE_DATA:
1488                         V_I4(pVarResult) = msiDoActionStatusFinished;
1489                         break;
1490                     case ERROR_INVALID_HANDLE_STATE:
1491                         V_I4(pVarResult) = msiDoActionStatusWrongState;
1492                         break;
1493                     case ERROR_INVALID_DATA:
1494                         V_I4(pVarResult) = msiDoActionStatusBadActionData;
1495                         break;
1496                     default:
1497                         VariantClear(&varg0);
1498                         FIXME("MsiDoAction returned unhandled value %d\n", ret);
1499                         return DISP_E_EXCEPTION;
1500                 }
1501             }
1502             else return DISP_E_MEMBERNOTFOUND;
1503             break;
1504 
1505         case DISPID_SESSION_EVALUATECONDITION:
1506             if (wFlags & DISPATCH_METHOD) {
1507                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1508                 if (FAILED(hr)) return hr;
1509                 V_VT(pVarResult) = VT_I4;
1510                 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1511             }
1512             else return DISP_E_MEMBERNOTFOUND;
1513             break;
1514 
1515         case DISPID_SESSION_MESSAGE:
1516             if(!(wFlags & DISPATCH_METHOD))
1517                 return DISP_E_MEMBERNOTFOUND;
1518 
1519             hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1520             if (FAILED(hr)) return hr;
1521             hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1522             if (FAILED(hr)) return hr;
1523 
1524             V_VT(pVarResult) = VT_I4;
1525             V_I4(pVarResult) =
1526                 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((struct automation_object *)V_DISPATCH(&varg1))->msiHandle);
1527             break;
1528 
1529         case DISPID_SESSION_SETINSTALLLEVEL:
1530             if (wFlags & DISPATCH_METHOD) {
1531                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1532                 if (FAILED(hr)) return hr;
1533                 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1534                 {
1535                     ERR("MsiSetInstallLevel returned %d\n", ret);
1536                     return DISP_E_EXCEPTION;
1537                 }
1538             }
1539             else return DISP_E_MEMBERNOTFOUND;
1540             break;
1541 
1542         case DISPID_SESSION_FEATURECURRENTSTATE:
1543             if (wFlags & DISPATCH_PROPERTYGET) {
1544                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1545                 if (FAILED(hr)) return hr;
1546                 V_VT(pVarResult) = VT_I4;
1547                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1548                     V_I4(pVarResult) = iInstalled;
1549                 else
1550                 {
1551                     ERR("MsiGetFeatureState returned %d\n", ret);
1552                     V_I4(pVarResult) = msiInstallStateUnknown;
1553                 }
1554             }
1555             else return DISP_E_MEMBERNOTFOUND;
1556             break;
1557 
1558         case DISPID_SESSION_FEATUREREQUESTSTATE:
1559             if (wFlags & DISPATCH_PROPERTYGET) {
1560                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1561                 if (FAILED(hr)) return hr;
1562                 V_VT(pVarResult) = VT_I4;
1563                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1564                     V_I4(pVarResult) = iAction;
1565                 else
1566                 {
1567                     ERR("MsiGetFeatureState returned %d\n", ret);
1568                     V_I4(pVarResult) = msiInstallStateUnknown;
1569                 }
1570             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1571                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1572                 if (FAILED(hr)) return hr;
1573                 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1574                 if (FAILED(hr)) {
1575                     VariantClear(&varg0);
1576                     return hr;
1577                 }
1578                 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1579                 {
1580                     VariantClear(&varg0);
1581                     ERR("MsiSetFeatureState returned %d\n", ret);
1582                     return DISP_E_EXCEPTION;
1583                 }
1584             }
1585             else return DISP_E_MEMBERNOTFOUND;
1586             break;
1587 
1588          default:
1589             return DISP_E_MEMBERNOTFOUND;
1590     }
1591 
1592     VariantClear(&varg1);
1593     VariantClear(&varg0);
1594 
1595     return S_OK;
1596 }
1597 
1598 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1599  * registry value type. Used by Installer::RegistryValue. */
variant_from_registry_value(VARIANT * pVarResult,DWORD dwType,LPBYTE lpData,DWORD dwSize)1600 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1601 {
1602     WCHAR *szString = (WCHAR *)lpData;
1603     LPWSTR szNewString = NULL;
1604     DWORD dwNewSize = 0;
1605     int idx;
1606 
1607     switch (dwType)
1608     {
1609         /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1610         case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1611             idx = (dwSize/sizeof(WCHAR))-1;
1612             while (idx >= 0 && !szString[idx]) idx--;
1613             for (; idx >= 0; idx--)
1614                 if (!szString[idx]) szString[idx] = '\n';
1615             /* fall through */
1616         case REG_SZ:
1617             V_VT(pVarResult) = VT_BSTR;
1618             V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1619             break;
1620 
1621         case REG_EXPAND_SZ:
1622             if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1623                 ERR("ExpandEnvironmentStrings returned error %lu\n", GetLastError());
1624             else if (!(szNewString = malloc(dwNewSize * sizeof(WCHAR))))
1625                 ERR("Out of memory\n");
1626             else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1627                 ERR("ExpandEnvironmentStrings returned error %lu\n", GetLastError());
1628             else
1629             {
1630                 V_VT(pVarResult) = VT_BSTR;
1631                 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1632             }
1633             free(szNewString);
1634             break;
1635 
1636         case REG_DWORD:
1637             V_VT(pVarResult) = VT_I4;
1638             V_I4(pVarResult) = *((DWORD *)lpData);
1639             break;
1640 
1641         case REG_QWORD:
1642             V_VT(pVarResult) = VT_BSTR;
1643             V_BSTR(pVarResult) = SysAllocString(L"(REG_\?\?)");   /* Weird string, don't know why native returns it */
1644             break;
1645 
1646         case REG_BINARY:
1647             V_VT(pVarResult) = VT_BSTR;
1648             V_BSTR(pVarResult) = SysAllocString(L"(REG_BINARY)");
1649             break;
1650 
1651         case REG_NONE:
1652             V_VT(pVarResult) = VT_EMPTY;
1653             break;
1654 
1655         default:
1656             FIXME("Unhandled registry value type %lu\n", dwType);
1657     }
1658 }
1659 
InstallerImpl_CreateRecord(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1660 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1661                                           DISPPARAMS* pDispParams,
1662                                           VARIANT* pVarResult,
1663                                           EXCEPINFO* pExcepInfo,
1664                                           UINT* puArgErr)
1665 {
1666     HRESULT hr;
1667     VARIANTARG varg0;
1668     MSIHANDLE hrec;
1669 
1670     if (!(wFlags & DISPATCH_METHOD))
1671         return DISP_E_MEMBERNOTFOUND;
1672 
1673     VariantInit(&varg0);
1674     hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1675     if (FAILED(hr))
1676         return hr;
1677 
1678     V_VT(pVarResult) = VT_DISPATCH;
1679 
1680     hrec = MsiCreateRecord(V_I4(&varg0));
1681     if (!hrec)
1682         return DISP_E_EXCEPTION;
1683 
1684     return create_record(hrec, &V_DISPATCH(pVarResult));
1685 }
1686 
InstallerImpl_OpenPackage(struct automation_object * This,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1687 static HRESULT InstallerImpl_OpenPackage(struct automation_object *This,
1688                                          WORD wFlags,
1689                                          DISPPARAMS* pDispParams,
1690                                          VARIANT* pVarResult,
1691                                          EXCEPINFO* pExcepInfo,
1692                                          UINT* puArgErr)
1693 {
1694     UINT ret;
1695     HRESULT hr;
1696     MSIHANDLE hpkg;
1697     IDispatch* dispatch;
1698     VARIANTARG varg0, varg1;
1699 
1700     if (!(wFlags & DISPATCH_METHOD))
1701         return DISP_E_MEMBERNOTFOUND;
1702 
1703     if (pDispParams->cArgs == 0)
1704         return DISP_E_TYPEMISMATCH;
1705 
1706     if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1707         return DISP_E_TYPEMISMATCH;
1708 
1709     VariantInit(&varg0);
1710     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1711     if (FAILED(hr))
1712         return hr;
1713 
1714     VariantInit(&varg1);
1715     if (pDispParams->cArgs == 2)
1716     {
1717         hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1718         if (FAILED(hr))
1719             goto done;
1720     }
1721     else
1722     {
1723         V_VT(&varg1) = VT_I4;
1724         V_I4(&varg1) = 0;
1725     }
1726 
1727     V_VT(pVarResult) = VT_DISPATCH;
1728 
1729     ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1730     if (ret != ERROR_SUCCESS)
1731     {
1732         hr = DISP_E_EXCEPTION;
1733         goto done;
1734     }
1735 
1736     hr = create_session(hpkg, &This->IDispatch_iface, &dispatch);
1737     if (SUCCEEDED(hr))
1738         V_DISPATCH(pVarResult) = dispatch;
1739 
1740 done:
1741     VariantClear(&varg0);
1742     VariantClear(&varg1);
1743     return hr;
1744 }
1745 
InstallerImpl_OpenProduct(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1746 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1747                                          DISPPARAMS* pDispParams,
1748                                          VARIANT* pVarResult,
1749                                          EXCEPINFO* pExcepInfo,
1750                                          UINT* puArgErr)
1751 {
1752     HRESULT hr;
1753     VARIANTARG varg0;
1754 
1755     if (!(wFlags & DISPATCH_METHOD))
1756         return DISP_E_MEMBERNOTFOUND;
1757 
1758     VariantInit(&varg0);
1759     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1760     if (FAILED(hr))
1761         return hr;
1762 
1763     FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1764 
1765     VariantInit(pVarResult);
1766 
1767     VariantClear(&varg0);
1768     return S_OK;
1769 }
1770 
InstallerImpl_OpenDatabase(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1771 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1772                                           DISPPARAMS* pDispParams,
1773                                           VARIANT* pVarResult,
1774                                           EXCEPINFO* pExcepInfo,
1775                                           UINT* puArgErr)
1776 {
1777     UINT ret;
1778     HRESULT hr;
1779     MSIHANDLE hdb;
1780     IDispatch* dispatch;
1781     VARIANTARG varg0, varg1;
1782 
1783     if (!(wFlags & DISPATCH_METHOD))
1784         return DISP_E_MEMBERNOTFOUND;
1785 
1786     VariantInit(&varg0);
1787     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1788     if (FAILED(hr))
1789         return hr;
1790 
1791     VariantInit(&varg1);
1792     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1793     if (FAILED(hr))
1794         goto done;
1795 
1796     V_VT(pVarResult) = VT_DISPATCH;
1797 
1798     ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1799     if (ret != ERROR_SUCCESS)
1800     {
1801         hr = DISP_E_EXCEPTION;
1802         goto done;
1803     }
1804 
1805     hr = create_database(hdb, &dispatch);
1806     if (SUCCEEDED(hr))
1807         V_DISPATCH(pVarResult) = dispatch;
1808 
1809 done:
1810     VariantClear(&varg0);
1811     VariantClear(&varg1);
1812     return hr;
1813 }
1814 
InstallerImpl_SummaryInformation(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1815 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1816                                                 DISPPARAMS* pDispParams,
1817                                                 VARIANT* pVarResult,
1818                                                 EXCEPINFO* pExcepInfo,
1819                                                 UINT* puArgErr)
1820 {
1821     UINT ret;
1822     HRESULT hr;
1823     MSIHANDLE hsuminfo;
1824     IDispatch *dispatch;
1825     VARIANTARG varg0, varg1;
1826 
1827     if (!(wFlags & DISPATCH_PROPERTYGET))
1828         return DISP_E_MEMBERNOTFOUND;
1829 
1830     VariantInit(&varg1);
1831     hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1832     if (FAILED(hr))
1833         return hr;
1834 
1835     VariantInit(&varg0);
1836     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1837     if (FAILED(hr))
1838         return hr;
1839 
1840     ret = MsiGetSummaryInformationW(0, V_BSTR(&varg0), V_I4(&varg1), &hsuminfo);
1841     VariantClear(&varg0);
1842     if (ret != ERROR_SUCCESS)
1843         return DISP_E_EXCEPTION;
1844 
1845     hr = create_summaryinfo(hsuminfo, &dispatch);
1846     if (FAILED(hr))
1847         return hr;
1848 
1849     V_VT(pVarResult) = VT_DISPATCH;
1850     V_DISPATCH(pVarResult) = dispatch;
1851     return S_OK;
1852 }
1853 
InstallerImpl_UILevel(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1854 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1855                                      DISPPARAMS* pDispParams,
1856                                      VARIANT* pVarResult,
1857                                      EXCEPINFO* pExcepInfo,
1858                                      UINT* puArgErr)
1859 {
1860     HRESULT hr;
1861     VARIANTARG varg0;
1862     INSTALLUILEVEL ui;
1863 
1864     if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1865         return DISP_E_MEMBERNOTFOUND;
1866 
1867     if (wFlags & DISPATCH_PROPERTYPUT)
1868     {
1869         VariantInit(&varg0);
1870         hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1871         if (FAILED(hr))
1872             return hr;
1873 
1874         ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1875         if (ui == INSTALLUILEVEL_NOCHANGE)
1876             return DISP_E_EXCEPTION;
1877     }
1878     else if (wFlags & DISPATCH_PROPERTYGET)
1879     {
1880         ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1881         if (ui == INSTALLUILEVEL_NOCHANGE)
1882             return DISP_E_EXCEPTION;
1883 
1884         V_VT(pVarResult) = VT_I4;
1885         V_I4(pVarResult) = ui;
1886     }
1887 
1888     return S_OK;
1889 }
1890 
InstallerImpl_EnableLog(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1891 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1892                                        DISPPARAMS* pDispParams,
1893                                        VARIANT* pVarResult,
1894                                        EXCEPINFO* pExcepInfo,
1895                                        UINT* puArgErr)
1896 {
1897     if (!(wFlags & DISPATCH_METHOD))
1898         return DISP_E_MEMBERNOTFOUND;
1899 
1900     FIXME("\n");
1901 
1902     VariantInit(pVarResult);
1903     return S_OK;
1904 }
1905 
InstallerImpl_InstallProduct(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1906 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1907                                             DISPPARAMS* pDispParams,
1908                                             VARIANT* pVarResult,
1909                                             EXCEPINFO* pExcepInfo,
1910                                             UINT* puArgErr)
1911 {
1912     UINT ret;
1913     HRESULT hr;
1914     VARIANTARG varg0, varg1;
1915 
1916     if (!(wFlags & DISPATCH_METHOD))
1917         return DISP_E_MEMBERNOTFOUND;
1918 
1919     VariantInit(&varg0);
1920     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1921     if (FAILED(hr))
1922         return hr;
1923 
1924     VariantInit(&varg1);
1925     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1926     if (FAILED(hr))
1927         goto done;
1928 
1929     ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1930     if (ret != ERROR_SUCCESS)
1931     {
1932         hr = DISP_E_EXCEPTION;
1933         goto done;
1934     }
1935 
1936 done:
1937     VariantClear(&varg0);
1938     VariantClear(&varg1);
1939     return hr;
1940 }
1941 
InstallerImpl_Version(WORD wFlags,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1942 static HRESULT InstallerImpl_Version(WORD wFlags,
1943                                      VARIANT* pVarResult,
1944                                      EXCEPINFO* pExcepInfo,
1945                                      UINT* puArgErr)
1946 {
1947     HRESULT hr;
1948     DLLVERSIONINFO verinfo;
1949     WCHAR version[MAX_PATH];
1950 
1951     if (!(wFlags & DISPATCH_PROPERTYGET))
1952         return DISP_E_MEMBERNOTFOUND;
1953 
1954     verinfo.cbSize = sizeof(DLLVERSIONINFO);
1955     hr = DllGetVersion(&verinfo);
1956     if (FAILED(hr))
1957         return hr;
1958 
1959     swprintf(version, ARRAY_SIZE(version), L"%d.%d.%d.%d", verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1960              verinfo.dwBuildNumber, verinfo.dwPlatformID);
1961 
1962     V_VT(pVarResult) = VT_BSTR;
1963     V_BSTR(pVarResult) = SysAllocString(version);
1964     return S_OK;
1965 }
1966 
InstallerImpl_LastErrorRecord(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1967 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1968                                              DISPPARAMS* pDispParams,
1969                                              VARIANT* pVarResult,
1970                                              EXCEPINFO* pExcepInfo,
1971                                              UINT* puArgErr)
1972 {
1973     if (!(wFlags & DISPATCH_METHOD))
1974         return DISP_E_MEMBERNOTFOUND;
1975 
1976     FIXME("\n");
1977 
1978     VariantInit(pVarResult);
1979     return S_OK;
1980 }
1981 
InstallerImpl_RegistryValue(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)1982 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1983                                            DISPPARAMS* pDispParams,
1984                                            VARIANT* pVarResult,
1985                                            EXCEPINFO* pExcepInfo,
1986                                            UINT* puArgErr)
1987 {
1988     UINT ret;
1989     HKEY hkey = NULL;
1990     HRESULT hr;
1991     UINT posValue;
1992     DWORD type, size;
1993     LPWSTR szString = NULL;
1994     VARIANTARG varg0, varg1, varg2;
1995 
1996     if (!(wFlags & DISPATCH_METHOD))
1997         return DISP_E_MEMBERNOTFOUND;
1998 
1999     VariantInit(&varg0);
2000     hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
2001     if (FAILED(hr))
2002         return hr;
2003 
2004     VariantInit(&varg1);
2005     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2006     if (FAILED(hr))
2007         goto done;
2008 
2009     /* Save valuePos so we can save puArgErr if we are unable to do our type
2010      * conversions.
2011      */
2012     posValue = 2;
2013     VariantInit(&varg2);
2014     hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
2015     if (FAILED(hr))
2016         goto done;
2017 
2018     if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
2019         V_I4(&varg0) <= REG_INDEX_DYN_DATA)
2020     {
2021         V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
2022     }
2023 
2024     ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
2025 
2026     /* Only VT_EMPTY case can do anything if the key doesn't exist. */
2027     if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
2028     {
2029         hr = DISP_E_BADINDEX;
2030         goto done;
2031     }
2032 
2033     /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
2034     switch (V_VT(&varg2))
2035     {
2036         /* Return VT_BOOL clarifying whether registry key exists or not. */
2037         case VT_EMPTY:
2038             V_VT(pVarResult) = VT_BOOL;
2039             V_BOOL(pVarResult) = (ret == ERROR_SUCCESS) ? VARIANT_TRUE : VARIANT_FALSE;
2040             break;
2041 
2042         /* Return the value of specified key if it exists. */
2043         case VT_BSTR:
2044             ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
2045                                    NULL, NULL, NULL, &size);
2046             if (ret != ERROR_SUCCESS)
2047             {
2048                 hr = DISP_E_BADINDEX;
2049                 goto done;
2050             }
2051 
2052             szString = malloc(size);
2053             if (!szString)
2054             {
2055                 hr = E_OUTOFMEMORY;
2056                 goto done;
2057             }
2058 
2059             ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
2060                                    &type, (LPBYTE)szString, &size);
2061             if (ret != ERROR_SUCCESS)
2062             {
2063                 free(szString);
2064                 hr = DISP_E_BADINDEX;
2065                 goto done;
2066             }
2067 
2068             variant_from_registry_value(pVarResult, type,
2069                                         (LPBYTE)szString, size);
2070             free(szString);
2071             break;
2072 
2073         /* Try to make it into VT_I4, can use VariantChangeType for this. */
2074         default:
2075             hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
2076             if (FAILED(hr))
2077             {
2078                 if (hr == DISP_E_TYPEMISMATCH)
2079                     *puArgErr = posValue;
2080 
2081                 goto done;
2082             }
2083 
2084             /* Retrieve class name or maximum value name or subkey name size. */
2085             if (!V_I4(&varg2))
2086                 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
2087                                        NULL, NULL, NULL, NULL, NULL, NULL);
2088             else if (V_I4(&varg2) > 0)
2089                 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
2090                                        NULL, NULL, &size, NULL, NULL, NULL);
2091             else /* V_I4(&varg2) < 0 */
2092                 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
2093                                        NULL, NULL, NULL, NULL, NULL, NULL);
2094 
2095             if (ret != ERROR_SUCCESS)
2096                 goto done;
2097 
2098             szString = malloc(++size * sizeof(WCHAR));
2099             if (!szString)
2100             {
2101                 hr = E_OUTOFMEMORY;
2102                 goto done;
2103             }
2104 
2105             if (!V_I4(&varg2))
2106                 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
2107                                        NULL, NULL, NULL, NULL, NULL, NULL);
2108             else if (V_I4(&varg2) > 0)
2109                 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
2110                                     &size, 0, 0, NULL, NULL);
2111             else /* V_I4(&varg2) < 0 */
2112                 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
2113 
2114             if (ret == ERROR_SUCCESS)
2115             {
2116                 V_VT(pVarResult) = VT_BSTR;
2117                 V_BSTR(pVarResult) = SysAllocString(szString);
2118             }
2119 
2120             free(szString);
2121     }
2122 
2123 done:
2124     VariantClear(&varg0);
2125     VariantClear(&varg1);
2126     VariantClear(&varg2);
2127     RegCloseKey(hkey);
2128     return hr;
2129 }
2130 
InstallerImpl_Environment(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)2131 static HRESULT InstallerImpl_Environment(WORD wFlags,
2132                                          DISPPARAMS* pDispParams,
2133                                          VARIANT* pVarResult,
2134                                          EXCEPINFO* pExcepInfo,
2135                                          UINT* puArgErr)
2136 {
2137     if (!(wFlags & DISPATCH_METHOD))
2138         return DISP_E_MEMBERNOTFOUND;
2139 
2140     FIXME("\n");
2141 
2142     VariantInit(pVarResult);
2143     return S_OK;
2144 }
2145 
InstallerImpl_FileAttributes(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)2146 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2147                                             DISPPARAMS* pDispParams,
2148                                             VARIANT* pVarResult,
2149                                             EXCEPINFO* pExcepInfo,
2150                                             UINT* puArgErr)
2151 {
2152     if (!(wFlags & DISPATCH_METHOD))
2153         return DISP_E_MEMBERNOTFOUND;
2154 
2155     FIXME("\n");
2156 
2157     VariantInit(pVarResult);
2158     return S_OK;
2159 }
2160 
InstallerImpl_FileSize(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)2161 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2162                                       DISPPARAMS* pDispParams,
2163                                       VARIANT* pVarResult,
2164                                       EXCEPINFO* pExcepInfo,
2165                                       UINT* puArgErr)
2166 {
2167     if (!(wFlags & DISPATCH_METHOD))
2168         return DISP_E_MEMBERNOTFOUND;
2169 
2170     FIXME("\n");
2171 
2172     VariantInit(pVarResult);
2173     return S_OK;
2174 }
2175 
InstallerImpl_FileVersion(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)2176 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2177                                          DISPPARAMS* pDispParams,
2178                                          VARIANT* pVarResult,
2179                                          EXCEPINFO* pExcepInfo,
2180                                          UINT* puArgErr)
2181 {
2182     if (!(wFlags & DISPATCH_METHOD))
2183         return DISP_E_MEMBERNOTFOUND;
2184 
2185     FIXME("\n");
2186 
2187     VariantInit(pVarResult);
2188     return S_OK;
2189 }
2190 
InstallerImpl_ProductState(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)2191 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2192                                           DISPPARAMS* pDispParams,
2193                                           VARIANT* pVarResult,
2194                                           EXCEPINFO* pExcepInfo,
2195                                           UINT* puArgErr)
2196 {
2197     HRESULT hr;
2198     VARIANTARG varg0;
2199 
2200     if (!(wFlags & DISPATCH_PROPERTYGET))
2201         return DISP_E_MEMBERNOTFOUND;
2202 
2203     VariantInit(&varg0);
2204     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2205     if (FAILED(hr))
2206         return hr;
2207 
2208     V_VT(pVarResult) = VT_I4;
2209     V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2210 
2211     VariantClear(&varg0);
2212     return S_OK;
2213 }
2214 
InstallerImpl_ProductInfo(WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)2215 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2216                                          DISPPARAMS* pDispParams,
2217                                          VARIANT* pVarResult,
2218                                          EXCEPINFO* pExcepInfo,
2219                                          UINT* puArgErr)
2220 {
2221     UINT ret;
2222     HRESULT hr;
2223     DWORD size;
2224     LPWSTR str = NULL;
2225     VARIANTARG varg0, varg1;
2226 
2227     if (!(wFlags & DISPATCH_PROPERTYGET))
2228         return DISP_E_MEMBERNOTFOUND;
2229 
2230     VariantInit(&varg0);
2231     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2232     if (FAILED(hr))
2233         return hr;
2234 
2235     VariantInit(&varg1);
2236     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2237     if (FAILED(hr))
2238         goto done;
2239 
2240     V_VT(pVarResult) = VT_BSTR;
2241     V_BSTR(pVarResult) = NULL;
2242 
2243     ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2244     if (ret != ERROR_SUCCESS)
2245     {
2246         hr = DISP_E_EXCEPTION;
2247         goto done;
2248     }
2249 
2250     str = malloc(++size * sizeof(WCHAR));
2251     if (!str)
2252     {
2253         hr = E_OUTOFMEMORY;
2254         goto done;
2255     }
2256 
2257     ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2258     if (ret != ERROR_SUCCESS)
2259     {
2260         hr = DISP_E_EXCEPTION;
2261         goto done;
2262     }
2263 
2264     V_BSTR(pVarResult) = SysAllocString(str);
2265     hr = S_OK;
2266 
2267 done:
2268     free(str);
2269     VariantClear(&varg0);
2270     VariantClear(&varg1);
2271     return hr;
2272 }
2273 
InstallerImpl_Products(WORD flags,DISPPARAMS * pDispParams,VARIANT * result,EXCEPINFO * pExcepInfo,UINT * puArgErr)2274 static HRESULT InstallerImpl_Products(WORD flags,
2275                                       DISPPARAMS* pDispParams,
2276                                       VARIANT* result,
2277                                       EXCEPINFO* pExcepInfo,
2278                                       UINT* puArgErr)
2279 {
2280     IDispatch *dispatch;
2281     HRESULT hr;
2282 
2283     if (!(flags & DISPATCH_PROPERTYGET))
2284         return DISP_E_MEMBERNOTFOUND;
2285 
2286     hr = create_list(NULL, &dispatch);
2287     if (FAILED(hr))
2288         return hr;
2289 
2290     V_VT(result) = VT_DISPATCH;
2291     V_DISPATCH(result) = dispatch;
2292 
2293     return hr;
2294 }
2295 
InstallerImpl_RelatedProducts(WORD flags,DISPPARAMS * pDispParams,VARIANT * result,EXCEPINFO * pExcepInfo,UINT * puArgErr)2296 static HRESULT InstallerImpl_RelatedProducts(WORD flags,
2297                                              DISPPARAMS* pDispParams,
2298                                              VARIANT* result,
2299                                              EXCEPINFO* pExcepInfo,
2300                                              UINT* puArgErr)
2301 {
2302     IDispatch* dispatch;
2303     VARIANTARG related;
2304     HRESULT hr;
2305 
2306     if (!(flags & DISPATCH_PROPERTYGET))
2307         return DISP_E_MEMBERNOTFOUND;
2308 
2309     VariantInit(&related);
2310     hr = DispGetParam(pDispParams, 0, VT_BSTR, &related, puArgErr);
2311     if (FAILED(hr))
2312         return hr;
2313 
2314     hr = create_list(V_BSTR(&related), &dispatch);
2315     VariantClear(&related);
2316 
2317     V_VT(result) = VT_DISPATCH;
2318     V_DISPATCH(result) = dispatch;
2319 
2320     return hr;
2321 }
2322 
installer_invoke(struct automation_object * This,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)2323 static HRESULT installer_invoke(
2324         struct automation_object *This,
2325         DISPID dispIdMember,
2326         REFIID riid,
2327         LCID lcid,
2328         WORD wFlags,
2329         DISPPARAMS* pDispParams,
2330         VARIANT* pVarResult,
2331         EXCEPINFO* pExcepInfo,
2332         UINT* puArgErr)
2333 {
2334     switch (dispIdMember)
2335     {
2336         case DISPID_INSTALLER_CREATERECORD:
2337             return InstallerImpl_CreateRecord(wFlags, pDispParams,
2338                                               pVarResult, pExcepInfo, puArgErr);
2339 
2340         case DISPID_INSTALLER_OPENPACKAGE:
2341             return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2342                                              pVarResult, pExcepInfo, puArgErr);
2343 
2344         case DISPID_INSTALLER_OPENPRODUCT:
2345             return InstallerImpl_OpenProduct(wFlags, pDispParams,
2346                                              pVarResult, pExcepInfo, puArgErr);
2347 
2348         case DISPID_INSTALLER_OPENDATABASE:
2349             return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2350                                               pVarResult, pExcepInfo, puArgErr);
2351 
2352         case DISPID_INSTALLER_SUMMARYINFORMATION:
2353             return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2354                                                     pVarResult, pExcepInfo,
2355                                                     puArgErr);
2356 
2357         case DISPID_INSTALLER_UILEVEL:
2358             return InstallerImpl_UILevel(wFlags, pDispParams,
2359                                          pVarResult, pExcepInfo, puArgErr);
2360 
2361         case DISPID_INSTALLER_ENABLELOG:
2362             return InstallerImpl_EnableLog(wFlags, pDispParams,
2363                                            pVarResult, pExcepInfo, puArgErr);
2364 
2365         case DISPID_INSTALLER_INSTALLPRODUCT:
2366             return InstallerImpl_InstallProduct(wFlags, pDispParams,
2367                                                 pVarResult, pExcepInfo,
2368                                                 puArgErr);
2369 
2370         case DISPID_INSTALLER_VERSION:
2371             return InstallerImpl_Version(wFlags, pVarResult,
2372                                          pExcepInfo, puArgErr);
2373 
2374         case DISPID_INSTALLER_LASTERRORRECORD:
2375             return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2376                                                  pVarResult, pExcepInfo,
2377                                                  puArgErr);
2378 
2379         case DISPID_INSTALLER_REGISTRYVALUE:
2380             return InstallerImpl_RegistryValue(wFlags, pDispParams,
2381                                                pVarResult, pExcepInfo,
2382                                                puArgErr);
2383 
2384         case DISPID_INSTALLER_ENVIRONMENT:
2385             return InstallerImpl_Environment(wFlags, pDispParams,
2386                                              pVarResult, pExcepInfo, puArgErr);
2387 
2388         case DISPID_INSTALLER_FILEATTRIBUTES:
2389             return InstallerImpl_FileAttributes(wFlags, pDispParams,
2390                                                 pVarResult, pExcepInfo,
2391                                                 puArgErr);
2392 
2393         case DISPID_INSTALLER_FILESIZE:
2394             return InstallerImpl_FileSize(wFlags, pDispParams,
2395                                           pVarResult, pExcepInfo, puArgErr);
2396 
2397         case DISPID_INSTALLER_FILEVERSION:
2398             return InstallerImpl_FileVersion(wFlags, pDispParams,
2399                                              pVarResult, pExcepInfo, puArgErr);
2400 
2401         case DISPID_INSTALLER_PRODUCTSTATE:
2402             return InstallerImpl_ProductState(wFlags, pDispParams,
2403                                               pVarResult, pExcepInfo, puArgErr);
2404 
2405         case DISPID_INSTALLER_PRODUCTINFO:
2406             return InstallerImpl_ProductInfo(wFlags, pDispParams,
2407                                              pVarResult, pExcepInfo, puArgErr);
2408 
2409         case DISPID_INSTALLER_PRODUCTS:
2410             return InstallerImpl_Products(wFlags, pDispParams,
2411                                           pVarResult, pExcepInfo, puArgErr);
2412 
2413         case DISPID_INSTALLER_RELATEDPRODUCTS:
2414             return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2415                                                  pVarResult, pExcepInfo,
2416                                                  puArgErr);
2417 
2418         default:
2419             return DISP_E_MEMBERNOTFOUND;
2420     }
2421 }
2422 
create_msiserver(IUnknown * outer,void ** ppObj)2423 HRESULT create_msiserver(IUnknown *outer, void **ppObj)
2424 {
2425     struct automation_object *installer;
2426 
2427     TRACE("(%p %p)\n", outer, ppObj);
2428 
2429     if (outer)
2430         return CLASS_E_NOAGGREGATION;
2431 
2432     installer = malloc(sizeof(*installer));
2433     if (!installer) return E_OUTOFMEMORY;
2434 
2435     init_automation_object(installer, 0, Installer_tid);
2436 
2437     *ppObj = &installer->IDispatch_iface;
2438 
2439     return S_OK;
2440 }
2441 
create_session(MSIHANDLE msiHandle,IDispatch * installer,IDispatch ** disp)2442 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp)
2443 {
2444     struct session_object *session;
2445 
2446     session = malloc(sizeof(*session));
2447     if (!session) return E_OUTOFMEMORY;
2448 
2449     init_automation_object(&session->autoobj, msiHandle, Session_tid);
2450 
2451     session->installer = installer;
2452     *disp = &session->autoobj.IDispatch_iface;
2453 
2454     return S_OK;
2455 }
2456 
create_database(MSIHANDLE msiHandle,IDispatch ** dispatch)2457 static HRESULT create_database(MSIHANDLE msiHandle, IDispatch **dispatch)
2458 {
2459     struct automation_object *database;
2460 
2461     TRACE("%lu %p\n", msiHandle, dispatch);
2462 
2463     database = malloc(sizeof(*database));
2464     if (!database) return E_OUTOFMEMORY;
2465 
2466     init_automation_object(database, msiHandle, Database_tid);
2467 
2468     *dispatch = &database->IDispatch_iface;
2469 
2470     return S_OK;
2471 }
2472 
create_view(MSIHANDLE msiHandle,IDispatch ** dispatch)2473 static HRESULT create_view(MSIHANDLE msiHandle, IDispatch **dispatch)
2474 {
2475     struct automation_object *view;
2476 
2477     TRACE("%lu %p\n", msiHandle, dispatch);
2478 
2479     view = malloc(sizeof(*view));
2480     if (!view) return E_OUTOFMEMORY;
2481 
2482     init_automation_object(view, msiHandle, View_tid);
2483 
2484     *dispatch = &view->IDispatch_iface;
2485 
2486     return S_OK;
2487 }
2488 
create_summaryinfo(MSIHANDLE msiHandle,IDispatch ** disp)2489 static HRESULT create_summaryinfo(MSIHANDLE msiHandle, IDispatch **disp)
2490 {
2491     struct automation_object *info;
2492 
2493     info = malloc(sizeof(*info));
2494     if (!info) return E_OUTOFMEMORY;
2495 
2496     init_automation_object(info, msiHandle, SummaryInfo_tid);
2497 
2498     *disp = &info->IDispatch_iface;
2499 
2500     return S_OK;
2501 }
2502