quartz: Exclude unused headers.
[wine] / dlls / msi / automation.c
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 "wine/debug.h"
34 #include "wine/unicode.h"
35
36 #include "msiserver.h"
37 #include "msiserver_dispids.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
40
41 /*
42  * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
43  *                    called from AutomationObject::Invoke, and pass this function to create_automation_object.
44  */
45
46 typedef interface AutomationObject AutomationObject;
47
48 interface AutomationObject {
49     /*
50      * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
51      */
52     const IDispatchVtbl *lpVtbl;
53     const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
54
55     /* Object reference count */
56     LONG ref;
57
58     /* Clsid for this class and it's appropriate ITypeInfo object */
59     LPCLSID clsid;
60     ITypeInfo *iTypeInfo;
61
62     /* The MSI handle of the current object */
63     MSIHANDLE msiHandle;
64
65     /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
66     HRESULT (STDMETHODCALLTYPE *funcInvoke)(
67         AutomationObject* This,
68         DISPID dispIdMember,
69         REFIID riid,
70         LCID lcid,
71         WORD wFlags,
72         DISPPARAMS* pDispParams,
73         VARIANT* pVarResult,
74         EXCEPINFO* pExcepInfo,
75         UINT* puArgErr);
76
77     /* A function that is called from AutomationObject::Release when the object is being freed to free any private
78      * data structures (or NULL) */
79     void (STDMETHODCALLTYPE *funcFree)(AutomationObject* This);
80 };
81
82 /*
83  * Structures for additional data required by specific automation objects
84  */
85
86 typedef struct {
87     int iCount;
88     LPWSTR *pszStrings;
89 } StringListData;
90
91 typedef struct {
92     /* The parent Installer object */
93     IDispatch *pInstaller;
94 } SessionData;
95
96 /* VTables */
97 static const struct IDispatchVtbl AutomationObject_Vtbl;
98 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
99
100 /* Load type info so we don't have to process GetIDsOfNames */
101 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
102 {
103     HRESULT hr;
104     LPTYPELIB pLib = NULL;
105     LPTYPEINFO pInfo = NULL;
106     static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
107
108     TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
109
110     /* Load registered type library */
111     hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
112     if (FAILED(hr)) {
113         hr = LoadTypeLib(szMsiServer, &pLib);
114         if (FAILED(hr)) {
115             ERR("Could not load msiserver.tlb\n");
116             return hr;
117         }
118     }
119
120     /* Get type information for object */
121     hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
122     ITypeLib_Release(pLib);
123     if (FAILED(hr)) {
124         ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
125         return hr;
126     }
127     *pptinfo = pInfo;
128     return S_OK;
129 }
130
131 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
132  * with the appropriate clsid and invocation function. */
133 HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
134             HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
135                                                     VARIANT*,EXCEPINFO*,UINT*),
136                                  void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
137                                  SIZE_T sizetPrivateData)
138 {
139     AutomationObject *object;
140     HRESULT hr;
141
142     TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
143
144     if( pUnkOuter )
145         return CLASS_E_NOAGGREGATION;
146
147     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData);
148
149     /* Set all the VTable references */
150     object->lpVtbl = &AutomationObject_Vtbl;
151     object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
152     object->ref = 1;
153
154     /* Store data that was passed */
155     object->msiHandle = msiHandle;
156     object->clsid = (LPCLSID)clsid;
157     object->funcInvoke = funcInvoke;
158     object->funcFree = funcFree;
159
160     /* Load our TypeInfo so we don't have to process GetIDsOfNames */
161     object->iTypeInfo = NULL;
162     hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
163     if (FAILED(hr)) {
164         HeapFree(GetProcessHeap(), 0, object);
165         return hr;
166     }
167
168     *ppObj = object;
169
170     return S_OK;
171 }
172
173 /* Macros to get pointer to AutomationObject from the other VTables. */
174 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
175 {
176     return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
177 }
178
179 /* Macro to get pointer to private object data */
180 static inline void *private_data( AutomationObject *This )
181 {
182     return This + 1;
183 }
184
185 /*
186  * AutomationObject methods
187  */
188
189 /*** IUnknown methods ***/
190 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
191 {
192     AutomationObject *This = (AutomationObject *)iface;
193
194     TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
195
196     if (ppvObject == NULL)
197       return E_INVALIDARG;
198
199     *ppvObject = 0;
200
201     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
202         *ppvObject = This;
203     else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
204              IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
205              IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
206         *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
207     else
208     {
209         TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
210         return E_NOINTERFACE;
211     }
212
213     /*
214      * Query Interface always increases the reference count by one when it is
215      * successful
216      */
217     IClassFactory_AddRef(iface);
218
219     return S_OK;
220 }
221
222 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
223 {
224     AutomationObject *This = (AutomationObject *)iface;
225
226     TRACE("(%p/%p)\n", iface, This);
227
228     return InterlockedIncrement(&This->ref);
229 }
230
231 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
232 {
233     AutomationObject *This = (AutomationObject *)iface;
234     ULONG ref = InterlockedDecrement(&This->ref);
235
236     TRACE("(%p/%p)\n", iface, This);
237
238     if (!ref)
239     {
240         if (This->funcFree) This->funcFree(This);
241         MsiCloseHandle(This->msiHandle);
242         HeapFree(GetProcessHeap(), 0, This);
243     }
244
245     return ref;
246 }
247
248 /*** IDispatch methods ***/
249 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
250         IDispatch* iface,
251         UINT* pctinfo)
252 {
253     AutomationObject *This = (AutomationObject *)iface;
254
255     TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
256     *pctinfo = 1;
257     return S_OK;
258 }
259
260 static HRESULT WINAPI AutomationObject_GetTypeInfo(
261         IDispatch* iface,
262         UINT iTInfo,
263         LCID lcid,
264         ITypeInfo** ppTInfo)
265 {
266     AutomationObject *This = (AutomationObject *)iface;
267     TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
268
269     ITypeInfo_AddRef(This->iTypeInfo);
270     *ppTInfo = This->iTypeInfo;
271     return S_OK;
272 }
273
274 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
275         IDispatch* iface,
276         REFIID riid,
277         LPOLESTR* rgszNames,
278         UINT cNames,
279         LCID lcid,
280         DISPID* rgDispId)
281 {
282     AutomationObject *This = (AutomationObject *)iface;
283     HRESULT hr;
284     TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
285
286     if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
287     hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
288     if (hr == DISP_E_UNKNOWNNAME)
289     {
290         int idx;
291         for (idx=0; idx<cNames; idx++)
292         {
293             if (rgDispId[idx] == DISPID_UNKNOWN)
294                 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
295         }
296     }
297     return hr;
298 }
299
300 /* Maximum number of allowed function parameters+1 */
301 #define MAX_FUNC_PARAMS 20
302
303 /* Some error checking is done here to simplify individual object function invocation */
304 static HRESULT WINAPI AutomationObject_Invoke(
305         IDispatch* iface,
306         DISPID dispIdMember,
307         REFIID riid,
308         LCID lcid,
309         WORD wFlags,
310         DISPPARAMS* pDispParams,
311         VARIANT* pVarResult,
312         EXCEPINFO* pExcepInfo,
313         UINT* puArgErr)
314 {
315     AutomationObject *This = (AutomationObject *)iface;
316     HRESULT hr;
317     unsigned int uArgErr;
318     VARIANT varResultDummy;
319     BSTR bstrName = NULL;
320
321     TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
322
323     if (!IsEqualIID(riid, &IID_NULL))
324     {
325         ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
326         return DISP_E_UNKNOWNNAME;
327     }
328
329     if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
330     {
331         ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
332         return DISP_E_PARAMNOTOPTIONAL;
333     }
334
335     /* This simplifies our individual object invocation functions */
336     if (puArgErr == NULL) puArgErr = &uArgErr;
337     if (pVarResult == NULL) pVarResult = &varResultDummy;
338
339     /* Assume return type is void unless determined otherwise */
340     VariantInit(pVarResult);
341
342     /* If we are tracing, we want to see the name of the member we are invoking */
343     if (TRACE_ON(msi))
344     {
345         ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
346         TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
347     }
348
349     hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
350
351     if (hr == DISP_E_MEMBERNOTFOUND) {
352         if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
353         FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
354     }
355     else if (pExcepInfo &&
356              (hr == DISP_E_PARAMNOTFOUND ||
357               hr == DISP_E_EXCEPTION)) {
358         static const WCHAR szComma[] = { ',',0 };
359         static WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
360         WCHAR szExceptionDescription[MAX_PATH];
361         BSTR bstrParamNames[MAX_FUNC_PARAMS];
362         unsigned namesNo, i;
363         BOOL bFirst = TRUE;
364
365         if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
366                                       MAX_FUNC_PARAMS, &namesNo)))
367         {
368             TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
369         }
370         else
371         {
372             memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
373             for (i=0; i<namesNo; i++)
374             {
375                 if (bFirst) bFirst = FALSE;
376                 else {
377                     lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
378                 }
379                 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
380                 SysFreeString(bstrParamNames[i]);
381             }
382
383             memset(pExcepInfo, 0, sizeof(EXCEPINFO));
384             pExcepInfo->wCode = 1000;
385             pExcepInfo->bstrSource = szExceptionSource;
386             pExcepInfo->bstrDescription = szExceptionDescription;
387             hr = DISP_E_EXCEPTION;
388         }
389     }
390
391     /* Make sure we free the return variant if it is our dummy variant */
392     if (pVarResult == &varResultDummy) VariantClear(pVarResult);
393
394     /* Free function name if we retrieved it */
395     if (bstrName) SysFreeString(bstrName);
396
397     TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
398
399     return hr;
400 }
401
402 static const struct IDispatchVtbl AutomationObject_Vtbl =
403 {
404     AutomationObject_QueryInterface,
405     AutomationObject_AddRef,
406     AutomationObject_Release,
407     AutomationObject_GetTypeInfoCount,
408     AutomationObject_GetTypeInfo,
409     AutomationObject_GetIDsOfNames,
410     AutomationObject_Invoke
411 };
412
413 /*
414  * IProvideMultipleClassInfo methods
415  */
416
417 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
418   IProvideMultipleClassInfo* iface,
419   REFIID     riid,
420   VOID**     ppvoid)
421 {
422     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
423     return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
424 }
425
426 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
427 {
428     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
429     return AutomationObject_AddRef((IDispatch *)This);
430 }
431
432 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
433 {
434     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
435     return AutomationObject_Release((IDispatch *)This);
436 }
437
438 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
439 {
440     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
441     TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
442     return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
443 }
444
445 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
446 {
447     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
448     TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
449
450     if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
451         return E_INVALIDARG;
452     else {
453         *pGUID = *This->clsid;
454         return S_OK;
455     }
456 }
457
458 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
459 {
460     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
461
462     TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
463     *pcti = 1;
464     return S_OK;
465 }
466
467 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
468         ULONG iti,
469         DWORD dwFlags,
470         ITypeInfo** pptiCoClass,
471         DWORD* pdwTIFlags,
472         ULONG* pcdispidReserved,
473         IID* piidPrimary,
474         IID* piidSource)
475 {
476     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
477
478     TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
479
480     if (iti != 0)
481         return E_INVALIDARG;
482
483     if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
484         load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
485
486     if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
487     {
488         *pdwTIFlags = 0;
489         *pcdispidReserved = 0;
490     }
491
492     if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
493         *piidPrimary = *This->clsid;
494     }
495
496     if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
497         *piidSource = *This->clsid;
498     }
499
500     return S_OK;
501 }
502
503 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
504 {
505     AutomationObject_IProvideMultipleClassInfo_QueryInterface,
506     AutomationObject_IProvideMultipleClassInfo_AddRef,
507     AutomationObject_IProvideMultipleClassInfo_Release,
508     AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
509     AutomationObject_IProvideMultipleClassInfo_GetGUID,
510     AutomationObject_GetMultiTypeInfoCount,
511     AutomationObject_GetInfoOfIndex
512 };
513
514 /*
515  * Individual Object Invocation Functions
516  */
517
518 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
519    This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
520    using DispGetParam/VariantChangeType. */
521 HRESULT WINAPI DispGetParam_CopyOnly(
522         DISPPARAMS *pdispparams, /* [in] Parameter list */
523         UINT        *position,    /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
524         VARIANT    *pvarResult)  /* [out] Destination for resulting variant */
525 {
526     /* position is counted backwards */
527     UINT pos;
528
529     TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
530           *position, pdispparams->cArgs, pdispparams->cNamedArgs);
531     if (*position < pdispparams->cArgs) {
532       /* positional arg? */
533       pos = pdispparams->cArgs - *position - 1;
534     } else {
535       /* FIXME: is this how to handle named args? */
536       for (pos=0; pos<pdispparams->cNamedArgs; pos++)
537         if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
538
539       if (pos==pdispparams->cNamedArgs)
540         return DISP_E_PARAMNOTFOUND;
541     }
542     *position = pos;
543     return VariantCopyInd(pvarResult,
544                         &pdispparams->rgvarg[pos]);
545 }
546
547 static HRESULT WINAPI RecordImpl_Invoke(
548         AutomationObject* This,
549         DISPID dispIdMember,
550         REFIID riid,
551         LCID lcid,
552         WORD wFlags,
553         DISPPARAMS* pDispParams,
554         VARIANT* pVarResult,
555         EXCEPINFO* pExcepInfo,
556         UINT* puArgErr)
557 {
558     WCHAR *szString;
559     DWORD dwLen;
560     UINT ret;
561     VARIANTARG varg0, varg1;
562     HRESULT hr;
563
564     VariantInit(&varg0);
565     VariantInit(&varg1);
566
567     switch (dispIdMember)
568     {
569         case DISPID_RECORD_FIELDCOUNT:
570             if (wFlags & DISPATCH_PROPERTYGET) {
571                 V_VT(pVarResult) = VT_I4;
572                 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
573             }
574             else return DISP_E_MEMBERNOTFOUND;
575             break;
576
577         case DISPID_RECORD_STRINGDATA:
578             if (wFlags & DISPATCH_PROPERTYGET) {
579                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
580                 if (FAILED(hr)) return hr;
581                 V_VT(pVarResult) = VT_BSTR;
582                 V_BSTR(pVarResult) = NULL;
583                 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
584                 {
585                     if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
586                         ERR("Out of memory\n");
587                     else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
588                         V_BSTR(pVarResult) = SysAllocString(szString);
589                     msi_free(szString);
590                 }
591                 if (ret != ERROR_SUCCESS)
592                     ERR("MsiRecordGetString returned %d\n", ret);
593             } else if (wFlags & DISPATCH_PROPERTYPUT) {
594                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
595                 if (FAILED(hr)) return hr;
596                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
597                 if (FAILED(hr)) return hr;
598                 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
599                 {
600                     VariantClear(&varg1);
601                     ERR("MsiRecordSetString returned %d\n", ret);
602                     return DISP_E_EXCEPTION;
603                 }
604             }
605             else return DISP_E_MEMBERNOTFOUND;
606             break;
607
608         case DISPID_RECORD_INTEGERDATA:
609             if (wFlags & DISPATCH_PROPERTYGET) {
610                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
611                 if (FAILED(hr)) return hr;
612                 V_VT(pVarResult) = VT_I4;
613                 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
614             } else if (wFlags & DISPATCH_PROPERTYPUT) {
615                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
616                 if (FAILED(hr)) return hr;
617                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
618                 if (FAILED(hr)) return hr;
619                 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
620                 {
621                     ERR("MsiRecordSetInteger returned %d\n", ret);
622                     return DISP_E_EXCEPTION;
623                 }
624             }
625             else return DISP_E_MEMBERNOTFOUND;
626             break;
627
628          default:
629             return DISP_E_MEMBERNOTFOUND;
630     }
631
632     VariantClear(&varg1);
633     VariantClear(&varg0);
634
635     return S_OK;
636 }
637
638 static HRESULT WINAPI StringListImpl_Invoke(
639         AutomationObject* This,
640         DISPID dispIdMember,
641         REFIID riid,
642         LCID lcid,
643         WORD wFlags,
644         DISPPARAMS* pDispParams,
645         VARIANT* pVarResult,
646         EXCEPINFO* pExcepInfo,
647         UINT* puArgErr)
648 {
649     StringListData *data = (StringListData *)private_data(This);
650     HRESULT hr;
651     VARIANTARG varg0;
652
653     VariantInit(&varg0);
654
655     switch (dispIdMember)
656     {
657          case DISPID_STRINGLIST_ITEM:
658             if (wFlags & DISPATCH_PROPERTYGET) {
659                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
660                 if (FAILED(hr)) return hr;
661                 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->iCount)
662                     return DISP_E_BADINDEX;
663                 V_VT(pVarResult) = VT_BSTR;
664                 V_BSTR(pVarResult) = SysAllocString(data->pszStrings[V_I4(&varg0)]);
665             }
666             else return DISP_E_MEMBERNOTFOUND;
667             break;
668
669          case DISPID_STRINGLIST_COUNT:
670             if (wFlags & DISPATCH_PROPERTYGET) {
671                 V_VT(pVarResult) = VT_I4;
672                 V_I4(pVarResult) = data->iCount;
673             }
674             else return DISP_E_MEMBERNOTFOUND;
675             break;
676
677          default:
678             return DISP_E_MEMBERNOTFOUND;
679     }
680
681     VariantClear(&varg0);
682
683     return S_OK;
684 }
685
686 static void WINAPI StringListImpl_Free(AutomationObject *This)
687 {
688     StringListData *data = private_data(This);
689     int idx;
690
691     for (idx=0; idx<data->iCount; idx++)
692         SysFreeString(data->pszStrings[idx]);
693     HeapFree(GetProcessHeap(), 0, data->pszStrings);
694 }
695
696 static HRESULT WINAPI ViewImpl_Invoke(
697         AutomationObject* This,
698         DISPID dispIdMember,
699         REFIID riid,
700         LCID lcid,
701         WORD wFlags,
702         DISPPARAMS* pDispParams,
703         VARIANT* pVarResult,
704         EXCEPINFO* pExcepInfo,
705         UINT* puArgErr)
706 {
707     MSIHANDLE msiHandle;
708     IDispatch *pDispatch = NULL;
709     UINT ret;
710     VARIANTARG varg0, varg1;
711     HRESULT hr;
712
713     VariantInit(&varg0);
714     VariantInit(&varg1);
715
716     switch (dispIdMember)
717     {
718         case DISPID_VIEW_EXECUTE:
719             if (wFlags & DISPATCH_METHOD)
720             {
721                 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
722                 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
723                     MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
724                 else
725                     MsiViewExecute(This->msiHandle, 0);
726             }
727             else return DISP_E_MEMBERNOTFOUND;
728             break;
729
730         case DISPID_VIEW_FETCH:
731             if (wFlags & DISPATCH_METHOD)
732             {
733                 V_VT(pVarResult) = VT_DISPATCH;
734                 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
735                 {
736                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
737                     {
738                         IDispatch_AddRef(pDispatch);
739                         V_DISPATCH(pVarResult) = pDispatch;
740                     }
741                     else
742                         ERR("Failed to create Record object, hresult 0x%08x\n", hr);
743                 }
744                 else if (ret == ERROR_NO_MORE_ITEMS)
745                     V_DISPATCH(pVarResult) = NULL;
746                 else
747                 {
748                     ERR("MsiViewFetch returned %d\n", ret);
749                     return DISP_E_EXCEPTION;
750                 }
751             }
752             else return DISP_E_MEMBERNOTFOUND;
753             break;
754
755         case DISPID_VIEW_MODIFY:
756             if (wFlags & DISPATCH_METHOD)
757             {
758                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
759                 if (FAILED(hr)) return hr;
760                 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
761                 if (FAILED(hr)) return hr;
762                 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
763                 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
764                 {
765                     VariantClear(&varg1);
766                     ERR("MsiViewModify returned %d\n", ret);
767                     return DISP_E_EXCEPTION;
768                 }
769             }
770             else return DISP_E_MEMBERNOTFOUND;
771             break;
772
773         case DISPID_VIEW_CLOSE:
774             if (wFlags & DISPATCH_METHOD)
775             {
776                 MsiViewClose(This->msiHandle);
777             }
778             else return DISP_E_MEMBERNOTFOUND;
779             break;
780
781          default:
782             return DISP_E_MEMBERNOTFOUND;
783     }
784
785     VariantClear(&varg1);
786     VariantClear(&varg0);
787
788     return S_OK;
789 }
790
791 static HRESULT WINAPI DatabaseImpl_Invoke(
792         AutomationObject* This,
793         DISPID dispIdMember,
794         REFIID riid,
795         LCID lcid,
796         WORD wFlags,
797         DISPPARAMS* pDispParams,
798         VARIANT* pVarResult,
799         EXCEPINFO* pExcepInfo,
800         UINT* puArgErr)
801 {
802     MSIHANDLE msiHandle;
803     IDispatch *pDispatch = NULL;
804     UINT ret;
805     VARIANTARG varg0, varg1;
806     HRESULT hr;
807
808     VariantInit(&varg0);
809     VariantInit(&varg1);
810
811     switch (dispIdMember)
812     {
813         case DISPID_DATABASE_OPENVIEW:
814             if (wFlags & DISPATCH_METHOD)
815             {
816                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
817                 if (FAILED(hr)) return hr;
818                 V_VT(pVarResult) = VT_DISPATCH;
819                 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
820                 {
821                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
822                     {
823                         IDispatch_AddRef(pDispatch);
824                         V_DISPATCH(pVarResult) = pDispatch;
825                     }
826                     else
827                         ERR("Failed to create View object, hresult 0x%08x\n", hr);
828                 }
829                 else
830                 {
831                     VariantClear(&varg0);
832                     ERR("MsiDatabaseOpenView returned %d\n", ret);
833                     return DISP_E_EXCEPTION;
834                 }
835             }
836             else return DISP_E_MEMBERNOTFOUND;
837             break;
838
839          default:
840             return DISP_E_MEMBERNOTFOUND;
841     }
842
843     VariantClear(&varg1);
844     VariantClear(&varg0);
845
846     return S_OK;
847 }
848
849 static HRESULT WINAPI SessionImpl_Invoke(
850         AutomationObject* This,
851         DISPID dispIdMember,
852         REFIID riid,
853         LCID lcid,
854         WORD wFlags,
855         DISPPARAMS* pDispParams,
856         VARIANT* pVarResult,
857         EXCEPINFO* pExcepInfo,
858         UINT* puArgErr)
859 {
860     SessionData *data = private_data(This);
861     WCHAR *szString;
862     DWORD dwLen;
863     IDispatch *pDispatch = NULL;
864     MSIHANDLE msiHandle;
865     LANGID langId;
866     UINT ret;
867     INSTALLSTATE iInstalled, iAction;
868     VARIANTARG varg0, varg1;
869     HRESULT hr;
870
871     VariantInit(&varg0);
872     VariantInit(&varg1);
873
874     switch (dispIdMember)
875     {
876         case DISPID_SESSION_INSTALLER:
877             if (wFlags & DISPATCH_PROPERTYGET) {
878                 V_VT(pVarResult) = VT_DISPATCH;
879                 IDispatch_AddRef(data->pInstaller);
880                 V_DISPATCH(pVarResult) = data->pInstaller;
881             }
882             else return DISP_E_MEMBERNOTFOUND;
883             break;
884
885         case DISPID_SESSION_PROPERTY:
886             if (wFlags & DISPATCH_PROPERTYGET) {
887                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
888                 if (FAILED(hr)) return hr;
889                 V_VT(pVarResult) = VT_BSTR;
890                 V_BSTR(pVarResult) = NULL;
891                 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
892                 {
893                     if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
894                         ERR("Out of memory\n");
895                     else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
896                         V_BSTR(pVarResult) = SysAllocString(szString);
897                     msi_free(szString);
898                 }
899                 if (ret != ERROR_SUCCESS)
900                     ERR("MsiGetProperty returned %d\n", ret);
901             } else if (wFlags & DISPATCH_PROPERTYPUT) {
902                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
903                 if (FAILED(hr)) return hr;
904                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
905                 if (FAILED(hr)) {
906                     VariantClear(&varg0);
907                     return hr;
908                 }
909                 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
910                 {
911                     VariantClear(&varg0);
912                     VariantClear(&varg1);
913                     ERR("MsiSetProperty returned %d\n", ret);
914                     return DISP_E_EXCEPTION;
915                 }
916             }
917             else return DISP_E_MEMBERNOTFOUND;
918             break;
919
920         case DISPID_SESSION_LANGUAGE:
921             if (wFlags & DISPATCH_PROPERTYGET) {
922                 langId = MsiGetLanguage(This->msiHandle);
923                 V_VT(pVarResult) = VT_I4;
924                 V_I4(pVarResult) = langId;
925             }
926             else return DISP_E_MEMBERNOTFOUND;
927             break;
928
929         case DISPID_SESSION_MODE:
930             if (wFlags & DISPATCH_PROPERTYGET) {
931                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
932                 if (FAILED(hr)) return hr;
933                 V_VT(pVarResult) = VT_BOOL;
934                 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
935             } else if (wFlags & DISPATCH_PROPERTYPUT) {
936                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
937                 if (FAILED(hr)) return hr;
938                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
939                 if (FAILED(hr)) return hr;
940                 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
941                 {
942                     ERR("MsiSetMode returned %d\n", ret);
943                     return DISP_E_EXCEPTION;
944                 }
945             }
946             else return DISP_E_MEMBERNOTFOUND;
947             break;
948
949         case DISPID_SESSION_DATABASE:
950             if (wFlags & DISPATCH_PROPERTYGET) {
951                 V_VT(pVarResult) = VT_DISPATCH;
952                 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
953                 {
954                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
955                     {
956                         IDispatch_AddRef(pDispatch);
957                         V_DISPATCH(pVarResult) = pDispatch;
958                     }
959                     else
960                         ERR("Failed to create Database object, hresult 0x%08x\n", hr);
961                 }
962                 else
963                 {
964                     ERR("MsiGetActiveDatabase failed\n");
965                     return DISP_E_EXCEPTION;
966                 }
967             }
968             else return DISP_E_MEMBERNOTFOUND;
969             break;
970
971         case DISPID_SESSION_DOACTION:
972             if (wFlags & DISPATCH_METHOD) {
973                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
974                 if (FAILED(hr)) return hr;
975                 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
976                 V_VT(pVarResult) = VT_I4;
977                 switch (ret)
978                 {
979                     case ERROR_FUNCTION_NOT_CALLED:
980                         V_I4(pVarResult) = msiDoActionStatusNoAction;
981                         break;
982                     case ERROR_SUCCESS:
983                         V_I4(pVarResult) = msiDoActionStatusSuccess;
984                         break;
985                     case ERROR_INSTALL_USEREXIT:
986                         V_I4(pVarResult) = msiDoActionStatusUserExit;
987                         break;
988                     case ERROR_INSTALL_FAILURE:
989                         V_I4(pVarResult) = msiDoActionStatusFailure;
990                         break;
991                     case ERROR_INSTALL_SUSPEND:
992                         V_I4(pVarResult) = msiDoActionStatusSuspend;
993                         break;
994                     case ERROR_MORE_DATA:
995                         V_I4(pVarResult) = msiDoActionStatusFinished;
996                         break;
997                     case ERROR_INVALID_HANDLE_STATE:
998                         V_I4(pVarResult) = msiDoActionStatusWrongState;
999                         break;
1000                     case ERROR_INVALID_DATA:
1001                         V_I4(pVarResult) = msiDoActionStatusBadActionData;
1002                         break;
1003                     default:
1004                         VariantClear(&varg0);
1005                         FIXME("MsiDoAction returned unhandled value %d\n", ret);
1006                         return DISP_E_EXCEPTION;
1007                 }
1008             }
1009             else return DISP_E_MEMBERNOTFOUND;
1010             break;
1011
1012         case DISPID_SESSION_EVALUATECONDITION:
1013             if (wFlags & DISPATCH_METHOD) {
1014                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1015                 if (FAILED(hr)) return hr;
1016                 V_VT(pVarResult) = VT_I4;
1017                 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1018             }
1019             else return DISP_E_MEMBERNOTFOUND;
1020             break;
1021
1022         case DISPID_SESSION_SETINSTALLLEVEL:
1023             if (wFlags & DISPATCH_METHOD) {
1024                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1025                 if (FAILED(hr)) return hr;
1026                 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1027                 {
1028                     ERR("MsiSetInstallLevel returned %d\n", ret);
1029                     return DISP_E_EXCEPTION;
1030                 }
1031             }
1032             else return DISP_E_MEMBERNOTFOUND;
1033             break;
1034
1035         case DISPID_SESSION_FEATURECURRENTSTATE:
1036             if (wFlags & DISPATCH_PROPERTYGET) {
1037                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1038                 if (FAILED(hr)) return hr;
1039                 V_VT(pVarResult) = VT_I4;
1040                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1041                     V_I4(pVarResult) = iInstalled;
1042                 else
1043                 {
1044                     ERR("MsiGetFeatureState returned %d\n", ret);
1045                     V_I4(pVarResult) = msiInstallStateUnknown;
1046                 }
1047             }
1048             else return DISP_E_MEMBERNOTFOUND;
1049             break;
1050
1051         case DISPID_SESSION_FEATUREREQUESTSTATE:
1052             if (wFlags & DISPATCH_PROPERTYGET) {
1053                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1054                 if (FAILED(hr)) return hr;
1055                 V_VT(pVarResult) = VT_I4;
1056                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1057                     V_I4(pVarResult) = iAction;
1058                 else
1059                 {
1060                     ERR("MsiGetFeatureState returned %d\n", ret);
1061                     V_I4(pVarResult) = msiInstallStateUnknown;
1062                 }
1063             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1064                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1065                 if (FAILED(hr)) return hr;
1066                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1067                 if (FAILED(hr)) {
1068                     VariantClear(&varg0);
1069                     return hr;
1070                 }
1071                 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1072                 {
1073                     VariantClear(&varg0);
1074                     ERR("MsiSetFeatureState returned %d\n", ret);
1075                     return DISP_E_EXCEPTION;
1076                 }
1077             }
1078             else return DISP_E_MEMBERNOTFOUND;
1079             break;
1080
1081          default:
1082             return DISP_E_MEMBERNOTFOUND;
1083     }
1084
1085     VariantClear(&varg1);
1086     VariantClear(&varg0);
1087
1088     return S_OK;
1089 }
1090
1091 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1092  * registry value type. Used by Installer::RegistryValue. */
1093 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1094 {
1095     static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1096     static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1097     WCHAR *szString = (WCHAR *)lpData;
1098     LPWSTR szNewString = NULL;
1099     DWORD dwNewSize = 0;
1100     int idx;
1101
1102     switch (dwType)
1103     {
1104         /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1105         case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1106             idx = (dwSize/sizeof(WCHAR))-1;
1107             while (idx >= 0 && !szString[idx]) idx--;
1108             for (; idx >= 0; idx--)
1109                 if (!szString[idx]) szString[idx] = '\n';
1110         case REG_SZ:
1111             V_VT(pVarResult) = VT_BSTR;
1112             V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1113             break;
1114
1115         case REG_EXPAND_SZ:
1116             if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1117                 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1118             else if (!(szNewString = msi_alloc(dwNewSize)))
1119                 ERR("Out of memory\n");
1120             else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1121                 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1122             else
1123             {
1124                 V_VT(pVarResult) = VT_BSTR;
1125                 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1126             }
1127             msi_free(szNewString);
1128             break;
1129
1130         case REG_DWORD:
1131             V_VT(pVarResult) = VT_I4;
1132             V_I4(pVarResult) = *((DWORD *)lpData);
1133             break;
1134
1135         case REG_QWORD:
1136             V_VT(pVarResult) = VT_BSTR;
1137             V_BSTR(pVarResult) = SysAllocString(szREG_);   /* Weird string, don't know why native returns it */
1138             break;
1139
1140         case REG_BINARY:
1141             V_VT(pVarResult) = VT_BSTR;
1142             V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1143             break;
1144
1145         case REG_NONE:
1146             V_VT(pVarResult) = VT_EMPTY;
1147             break;
1148
1149         default:
1150             FIXME("Unhandled registry value type %d\n", dwType);
1151     }
1152 }
1153
1154 static HRESULT WINAPI InstallerImpl_Invoke(
1155         AutomationObject* 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     IDispatch *pDispatch = NULL;
1167     UINT ret;
1168     VARIANTARG varg0, varg1, varg2;
1169     HRESULT hr;
1170
1171     VariantInit(&varg0);
1172     VariantInit(&varg1);
1173     VariantInit(&varg2);
1174
1175     switch (dispIdMember)
1176     {
1177         case DISPID_INSTALLER_CREATERECORD:
1178             if (wFlags & DISPATCH_METHOD)
1179             {
1180                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1181                 if (FAILED(hr)) return hr;
1182                 V_VT(pVarResult) = VT_DISPATCH;
1183                 if ((msiHandle = MsiCreateRecord(V_I4(&varg0))))
1184                 {
1185                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1186                     {
1187                         IDispatch_AddRef(pDispatch);
1188                         V_DISPATCH(pVarResult) = pDispatch;
1189                     }
1190                     else
1191                         ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1192                 }
1193                 else
1194                 {
1195                     ERR("MsiCreateRecord failed\n");
1196                     return DISP_E_EXCEPTION;
1197                 }
1198             }
1199             else return DISP_E_MEMBERNOTFOUND;
1200             break;
1201
1202         case DISPID_INSTALLER_OPENPACKAGE:
1203             if (wFlags & DISPATCH_METHOD)
1204             {
1205                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1206                 if (FAILED(hr)) return hr;
1207                 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1208                 if (FAILED(hr))
1209                 {
1210                     VariantClear(&varg0);
1211                     return hr;
1212                 }
1213                 V_VT(pVarResult) = VT_DISPATCH;
1214                 if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
1215                 {
1216                     if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
1217                     {
1218                         IDispatch_AddRef(pDispatch);
1219                         V_DISPATCH(pVarResult) = pDispatch;
1220                     }
1221                     else
1222                         ERR("Failed to create Session object, hresult 0x%08x\n", hr);
1223                 }
1224                 else
1225                 {
1226                     VariantClear(&varg0);
1227                     ERR("MsiOpenPackageEx returned %d\n", ret);
1228                     return DISP_E_EXCEPTION;
1229                 }
1230             }
1231             else return DISP_E_MEMBERNOTFOUND;
1232             break;
1233
1234         case DISPID_INSTALLER_INSTALLPRODUCT:
1235             if (wFlags & DISPATCH_METHOD)
1236             {
1237                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1238                 if (FAILED(hr)) return hr;
1239                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1240                 if (FAILED(hr))
1241                 {
1242                     VariantClear(&varg0);
1243                     return hr;
1244                 }
1245                 if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1246                 {
1247                     VariantClear(&varg1);
1248                     VariantClear(&varg0);
1249                     ERR("MsiInstallProduct returned %d\n", ret);
1250                     return DISP_E_EXCEPTION;
1251                 }
1252             }
1253             else return DISP_E_MEMBERNOTFOUND;
1254             break;
1255
1256         case DISPID_INSTALLER_REGISTRYVALUE:
1257             if (wFlags & DISPATCH_METHOD) {
1258                 HKEY hkey;
1259                 LPWSTR szString = NULL;
1260                 DWORD dwSize = 0, dwType;
1261                 UINT posValue = 2;    /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1262
1263                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1264                 if (FAILED(hr)) return hr;
1265                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1266                 if (FAILED(hr)) return hr;
1267                 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1268                 if (FAILED(hr))
1269                 {
1270                     VariantClear(&varg1);
1271                     return hr;
1272                 }
1273                 ret = RegOpenKeyW((HKEY)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1274
1275                 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1276                 switch (V_VT(&varg2))
1277                 {
1278                     case VT_EMPTY:  /* Return VT_BOOL as to whether or not registry key exists */
1279                         V_VT(pVarResult) = VT_BOOL;
1280                         V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1281                         break;
1282
1283                     case VT_BSTR:   /* Return value of specified key if it exists */
1284                         if (ret == ERROR_SUCCESS &&
1285                             (ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, NULL, NULL, &dwSize)) == ERROR_SUCCESS)
1286                         {
1287                             if (!(szString = msi_alloc(dwSize)))
1288                                 ERR("Out of memory\n");
1289                             else if ((ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, &dwType, (LPBYTE)szString, &dwSize)) == ERROR_SUCCESS)
1290                                 variant_from_registry_value(pVarResult, dwType, (LPBYTE)szString, dwSize);
1291                         }
1292
1293                         if (ret != ERROR_SUCCESS)
1294                         {
1295                             msi_free(szString);
1296                             VariantClear(&varg2);
1297                             VariantClear(&varg1);
1298                             return DISP_E_BADINDEX;
1299                         }
1300                         break;
1301
1302                     default:     /* Try to make it into VT_I4, can use VariantChangeType for this */
1303                         hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1304                         if (SUCCEEDED(hr) && ret != ERROR_SUCCESS) hr = DISP_E_BADINDEX; /* Conversion fine, but couldn't find key */
1305                         if (FAILED(hr))
1306                         {
1307                             if (hr == DISP_E_TYPEMISMATCH) *puArgErr = posValue;
1308                             VariantClear(&varg2);   /* Unknown type, so let's clear it */
1309                             VariantClear(&varg1);
1310                             return hr;
1311                         }
1312
1313                         /* Retrieve class name or maximum value name or subkey name size */
1314                         if (!V_I4(&varg2))
1315                             ret = RegQueryInfoKeyW(hkey, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1316                         else if (V_I4(&varg2) > 0)
1317                             ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL);
1318                         else /* V_I4(&varg2) < 0 */
1319                             ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
1320
1321                         if (ret == ERROR_SUCCESS)
1322                         {
1323                             if (!(szString = msi_alloc(++dwSize * sizeof(WCHAR))))
1324                                 ERR("Out of memory\n");
1325                             else if (!V_I4(&varg2))
1326                                 ret = RegQueryInfoKeyW(hkey, szString, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1327                             else if (V_I4(&varg2) > 0)
1328                                 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString, &dwSize, 0, 0, NULL, NULL);
1329                             else /* V_I4(&varg2) < 0 */
1330                                 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, dwSize);
1331
1332                             if (szString && ret == ERROR_SUCCESS)
1333                             {
1334                                 V_VT(pVarResult) = VT_BSTR;
1335                                 V_BSTR(pVarResult) = SysAllocString(szString);
1336                             }
1337                         }
1338                 }
1339
1340                 msi_free(szString);
1341                 RegCloseKey(hkey);
1342             }
1343             else return DISP_E_MEMBERNOTFOUND;
1344             break;
1345
1346         case DISPID_INSTALLER_PRODUCTSTATE:
1347             if (wFlags & DISPATCH_PROPERTYGET) {
1348                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1349                 if (FAILED(hr)) return hr;
1350                 V_VT(pVarResult) = VT_I4;
1351                 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
1352             }
1353             else return DISP_E_MEMBERNOTFOUND;
1354             break;
1355
1356         case DISPID_INSTALLER_PRODUCTS:
1357             if (wFlags & DISPATCH_PROPERTYGET)
1358             {
1359                 StringListData *sldata = NULL;
1360                 int idx = 0;
1361                 WCHAR szProductBuf[GUID_SIZE];
1362
1363                 /* Find number of products */
1364                 while ((ret = MsiEnumProductsW(idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1365                 if (ret != ERROR_NO_MORE_ITEMS)
1366                 {
1367                     ERR("MsiEnumProducts returned %d\n", ret);
1368                     return DISP_E_EXCEPTION;
1369                 }
1370
1371                 V_VT(pVarResult) = VT_DISPATCH;
1372                 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, StringListImpl_Invoke, StringListImpl_Free, sizeof(StringListData))))
1373                 {
1374                     IDispatch_AddRef(pDispatch);
1375                     V_DISPATCH(pVarResult) = pDispatch;
1376
1377                     /* Save product strings */
1378                     sldata = (StringListData *)private_data((AutomationObject *)pDispatch);
1379                     if (!(sldata->pszStrings = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LPWSTR)*sldata->iCount)))
1380                         ERR("Out of memory\n");
1381                     else
1382                     {
1383                         sldata->iCount = idx;
1384                         for (idx = 0; idx < sldata->iCount; idx++)
1385                         {
1386                             ret = MsiEnumProductsW(idx, szProductBuf);
1387                             sldata->pszStrings[idx] = SysAllocString(szProductBuf);
1388                         }
1389                     }
1390                 }
1391                 else
1392                     ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1393             }
1394             else return DISP_E_MEMBERNOTFOUND;
1395             break;
1396
1397         case DISPID_INSTALLER_RELATEDPRODUCTS:
1398             if (wFlags & DISPATCH_PROPERTYGET)
1399             {
1400                 StringListData *sldata = NULL;
1401                 int idx = 0;
1402                 WCHAR szProductBuf[GUID_SIZE];
1403
1404                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1405                 if (FAILED(hr)) return hr;
1406
1407                 /* Find number of related products */
1408                 while ((ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1409                 if (ret != ERROR_NO_MORE_ITEMS)
1410                 {
1411                     VariantClear(&varg0);
1412                     ERR("MsiEnumRelatedProducts returned %d\n", ret);
1413                     return DISP_E_EXCEPTION;
1414                 }
1415
1416                 V_VT(pVarResult) = VT_DISPATCH;
1417                 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, StringListImpl_Invoke, StringListImpl_Free, sizeof(StringListData))))
1418                 {
1419                     IDispatch_AddRef(pDispatch);
1420                     V_DISPATCH(pVarResult) = pDispatch;
1421
1422                     /* Save product strings */
1423                     sldata = (StringListData *)private_data((AutomationObject *)pDispatch);
1424                     if (!(sldata->pszStrings = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LPWSTR)*sldata->iCount)))
1425                         ERR("Out of memory\n");
1426                     else
1427                     {
1428                         sldata->iCount = idx;
1429                         for (idx = 0; idx < sldata->iCount; idx++)
1430                         {
1431                             ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf);
1432                             sldata->pszStrings[idx] = SysAllocString(szProductBuf);
1433                         }
1434                     }
1435                 }
1436                 else
1437                     ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1438             }
1439             else return DISP_E_MEMBERNOTFOUND;
1440             break;
1441
1442          default:
1443             return DISP_E_MEMBERNOTFOUND;
1444     }
1445
1446     VariantClear(&varg2);
1447     VariantClear(&varg1);
1448     VariantClear(&varg0);
1449
1450     return S_OK;
1451 }
1452
1453 /* Wrapper around create_automation_object to create an installer object. */
1454 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
1455 {
1456     return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
1457 }
1458
1459 /* Wrapper around create_automation_object to create a session object. */
1460 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
1461 {
1462     HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
1463     if (SUCCEEDED(hr) && pDispatch && *pDispatch)
1464         ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
1465     return hr;
1466 }