msi: Use struct instead of interface in object declarations.
[wine.git] / dlls / msi / automation.c
blob1be56b1765351246caa72c309e857acb95b182fc
1 /*
2 * Implementation of OLE Automation for Microsoft Installer (msi.dll)
4 * Copyright 2007 Misha Koshelev
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.
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.
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
21 #define COBJMACROS
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 #include "wine/unicode.h"
37 #include "msiserver.h"
38 #include "msiserver_dispids.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42 #define REG_INDEX_CLASSES_ROOT 0
43 #define REG_INDEX_DYN_DATA 6
46 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
47 * called from AutomationObject::Invoke, and pass this function to create_automation_object.
50 typedef struct AutomationObject AutomationObject;
52 struct AutomationObject {
54 * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
56 const IDispatchVtbl *lpVtbl;
57 const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
59 /* Object reference count */
60 LONG ref;
62 /* Clsid for this class and it's appropriate ITypeInfo object */
63 LPCLSID clsid;
64 ITypeInfo *iTypeInfo;
66 /* The MSI handle of the current object */
67 MSIHANDLE msiHandle;
69 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
70 HRESULT (STDMETHODCALLTYPE *funcInvoke)(
71 AutomationObject* This,
72 DISPID dispIdMember,
73 REFIID riid,
74 LCID lcid,
75 WORD wFlags,
76 DISPPARAMS* pDispParams,
77 VARIANT* pVarResult,
78 EXCEPINFO* pExcepInfo,
79 UINT* puArgErr);
81 /* A function that is called from AutomationObject::Release when the object is being freed to free any private
82 * data structures (or NULL) */
83 void (STDMETHODCALLTYPE *funcFree)(AutomationObject* This);
87 * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
90 typedef struct {
91 /* VTables */
92 const IEnumVARIANTVtbl *lpVtbl;
94 /* Object reference count */
95 LONG ref;
97 /* Current position and pointer to AutomationObject that stores actual data */
98 ULONG ulPos;
99 AutomationObject *pObj;
100 } ListEnumerator;
103 * Structures for additional data required by specific automation objects
106 typedef struct {
107 ULONG ulCount;
108 VARIANT *pVars;
109 } ListData;
111 typedef struct {
112 /* The parent Installer object */
113 IDispatch *pInstaller;
114 } SessionData;
116 /* VTables */
117 static const struct IDispatchVtbl AutomationObject_Vtbl;
118 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
119 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl;
121 /* Load type info so we don't have to process GetIDsOfNames */
122 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
124 HRESULT hr;
125 LPTYPELIB pLib = NULL;
126 LPTYPEINFO pInfo = NULL;
127 static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
129 TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
131 /* Load registered type library */
132 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
133 if (FAILED(hr)) {
134 hr = LoadTypeLib(szMsiServer, &pLib);
135 if (FAILED(hr)) {
136 ERR("Could not load msiserver.tlb\n");
137 return hr;
141 /* Get type information for object */
142 hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
143 ITypeLib_Release(pLib);
144 if (FAILED(hr)) {
145 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
146 return hr;
148 *pptinfo = pInfo;
149 return S_OK;
152 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
153 * with the appropriate clsid and invocation function. */
154 static HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
155 HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
156 VARIANT*,EXCEPINFO*,UINT*),
157 void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
158 SIZE_T sizetPrivateData)
160 AutomationObject *object;
161 HRESULT hr;
163 TRACE("(%d,%p,%p,%s,%p,%p,%ld)\n", msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
165 if( pUnkOuter )
166 return CLASS_E_NOAGGREGATION;
168 object = msi_alloc_zero( sizeof(AutomationObject) + sizetPrivateData );
170 /* Set all the VTable references */
171 object->lpVtbl = &AutomationObject_Vtbl;
172 object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
173 object->ref = 1;
175 /* Store data that was passed */
176 object->msiHandle = msiHandle;
177 object->clsid = (LPCLSID)clsid;
178 object->funcInvoke = funcInvoke;
179 object->funcFree = funcFree;
181 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
182 object->iTypeInfo = NULL;
183 hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
184 if (FAILED(hr)) {
185 msi_free( object );
186 return hr;
189 *ppObj = object;
191 return S_OK;
194 /* Create a list enumerator, placing the result in the pointer ppObj. */
195 static HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos)
197 ListEnumerator *object;
199 TRACE("(%p,%p,%p,%uld)\n", pUnkOuter, ppObj, pObj, ulPos);
201 if( pUnkOuter )
202 return CLASS_E_NOAGGREGATION;
204 object = msi_alloc_zero( sizeof(ListEnumerator) );
206 /* Set all the VTable references */
207 object->lpVtbl = &ListEnumerator_Vtbl;
208 object->ref = 1;
210 /* Store data that was passed */
211 object->ulPos = ulPos;
212 object->pObj = pObj;
213 if (pObj) IDispatch_AddRef((IDispatch *)pObj);
215 *ppObj = object;
216 return S_OK;
219 /* Macros to get pointer to AutomationObject from the other VTables. */
220 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
222 return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
225 /* Macro to get pointer to private object data */
226 static inline void *private_data( AutomationObject *This )
228 return This + 1;
232 * AutomationObject methods
235 /*** IUnknown methods ***/
236 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
238 AutomationObject *This = (AutomationObject *)iface;
240 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
242 if (ppvObject == NULL)
243 return E_INVALIDARG;
245 *ppvObject = 0;
247 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
248 *ppvObject = This;
249 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
250 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
251 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
252 *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
253 else
255 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
256 return E_NOINTERFACE;
260 * Query Interface always increases the reference count by one when it is
261 * successful
263 IClassFactory_AddRef(iface);
265 return S_OK;
268 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
270 AutomationObject *This = (AutomationObject *)iface;
272 TRACE("(%p/%p)\n", iface, This);
274 return InterlockedIncrement(&This->ref);
277 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
279 AutomationObject *This = (AutomationObject *)iface;
280 ULONG ref = InterlockedDecrement(&This->ref);
282 TRACE("(%p/%p)\n", iface, This);
284 if (!ref)
286 if (This->funcFree) This->funcFree(This);
287 ITypeInfo_Release(This->iTypeInfo);
288 MsiCloseHandle(This->msiHandle);
289 msi_free(This);
292 return ref;
295 /*** IDispatch methods ***/
296 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
297 IDispatch* iface,
298 UINT* pctinfo)
300 AutomationObject *This = (AutomationObject *)iface;
302 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
303 *pctinfo = 1;
304 return S_OK;
307 static HRESULT WINAPI AutomationObject_GetTypeInfo(
308 IDispatch* iface,
309 UINT iTInfo,
310 LCID lcid,
311 ITypeInfo** ppTInfo)
313 AutomationObject *This = (AutomationObject *)iface;
314 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
316 ITypeInfo_AddRef(This->iTypeInfo);
317 *ppTInfo = This->iTypeInfo;
318 return S_OK;
321 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
322 IDispatch* iface,
323 REFIID riid,
324 LPOLESTR* rgszNames,
325 UINT cNames,
326 LCID lcid,
327 DISPID* rgDispId)
329 AutomationObject *This = (AutomationObject *)iface;
330 HRESULT hr;
331 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
333 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
334 hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
335 if (hr == DISP_E_UNKNOWNNAME)
337 UINT idx;
338 for (idx=0; idx<cNames; idx++)
340 if (rgDispId[idx] == DISPID_UNKNOWN)
341 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
344 return hr;
347 /* Maximum number of allowed function parameters+1 */
348 #define MAX_FUNC_PARAMS 20
350 /* Some error checking is done here to simplify individual object function invocation */
351 static HRESULT WINAPI AutomationObject_Invoke(
352 IDispatch* iface,
353 DISPID dispIdMember,
354 REFIID riid,
355 LCID lcid,
356 WORD wFlags,
357 DISPPARAMS* pDispParams,
358 VARIANT* pVarResult,
359 EXCEPINFO* pExcepInfo,
360 UINT* puArgErr)
362 AutomationObject *This = (AutomationObject *)iface;
363 HRESULT hr;
364 unsigned int uArgErr;
365 VARIANT varResultDummy;
366 BSTR bstrName = NULL;
368 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
370 if (!IsEqualIID(riid, &IID_NULL))
372 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
373 return DISP_E_UNKNOWNNAME;
376 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
378 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
379 return DISP_E_PARAMNOTOPTIONAL;
382 /* This simplifies our individual object invocation functions */
383 if (puArgErr == NULL) puArgErr = &uArgErr;
384 if (pVarResult == NULL) pVarResult = &varResultDummy;
386 /* Assume return type is void unless determined otherwise */
387 VariantInit(pVarResult);
389 /* If we are tracing, we want to see the name of the member we are invoking */
390 if (TRACE_ON(msi))
392 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
393 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
396 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
398 if (hr == DISP_E_MEMBERNOTFOUND) {
399 if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
400 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
402 else if (pExcepInfo &&
403 (hr == DISP_E_PARAMNOTFOUND ||
404 hr == DISP_E_EXCEPTION)) {
405 static const WCHAR szComma[] = { ',',0 };
406 static const WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
407 WCHAR szExceptionDescription[MAX_PATH];
408 BSTR bstrParamNames[MAX_FUNC_PARAMS];
409 unsigned namesNo, i;
410 BOOL bFirst = TRUE;
412 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
413 MAX_FUNC_PARAMS, &namesNo)))
415 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
417 else
419 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
420 for (i=0; i<namesNo; i++)
422 if (bFirst) bFirst = FALSE;
423 else {
424 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
426 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
427 SysFreeString(bstrParamNames[i]);
430 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
431 pExcepInfo->wCode = 1000;
432 pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
433 pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
434 hr = DISP_E_EXCEPTION;
438 /* Make sure we free the return variant if it is our dummy variant */
439 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
441 /* Free function name if we retrieved it */
442 SysFreeString(bstrName);
444 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
446 return hr;
449 static const struct IDispatchVtbl AutomationObject_Vtbl =
451 AutomationObject_QueryInterface,
452 AutomationObject_AddRef,
453 AutomationObject_Release,
454 AutomationObject_GetTypeInfoCount,
455 AutomationObject_GetTypeInfo,
456 AutomationObject_GetIDsOfNames,
457 AutomationObject_Invoke
461 * IProvideMultipleClassInfo methods
464 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
465 IProvideMultipleClassInfo* iface,
466 REFIID riid,
467 VOID** ppvoid)
469 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
470 return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
473 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
475 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
476 return AutomationObject_AddRef((IDispatch *)This);
479 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
481 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
482 return AutomationObject_Release((IDispatch *)This);
485 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
487 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
488 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
489 return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
492 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
494 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
495 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
497 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
498 return E_INVALIDARG;
499 else {
500 *pGUID = *This->clsid;
501 return S_OK;
505 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
507 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
509 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
510 *pcti = 1;
511 return S_OK;
514 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
515 ULONG iti,
516 DWORD dwFlags,
517 ITypeInfo** pptiCoClass,
518 DWORD* pdwTIFlags,
519 ULONG* pcdispidReserved,
520 IID* piidPrimary,
521 IID* piidSource)
523 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
525 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
527 if (iti != 0)
528 return E_INVALIDARG;
530 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
531 load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
533 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
535 *pdwTIFlags = 0;
536 *pcdispidReserved = 0;
539 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
540 *piidPrimary = *This->clsid;
543 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
544 *piidSource = *This->clsid;
547 return S_OK;
550 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
552 AutomationObject_IProvideMultipleClassInfo_QueryInterface,
553 AutomationObject_IProvideMultipleClassInfo_AddRef,
554 AutomationObject_IProvideMultipleClassInfo_Release,
555 AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
556 AutomationObject_IProvideMultipleClassInfo_GetGUID,
557 AutomationObject_GetMultiTypeInfoCount,
558 AutomationObject_GetInfoOfIndex
562 * ListEnumerator methods
565 /*** IUnknown methods ***/
566 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, void** ppvObject)
568 ListEnumerator *This = (ListEnumerator *)iface;
570 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
572 if (ppvObject == NULL)
573 return E_INVALIDARG;
575 *ppvObject = 0;
577 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT))
578 *ppvObject = This;
579 else
581 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
582 return E_NOINTERFACE;
585 IClassFactory_AddRef(iface);
586 return S_OK;
589 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
591 ListEnumerator *This = (ListEnumerator *)iface;
593 TRACE("(%p/%p)\n", iface, This);
595 return InterlockedIncrement(&This->ref);
598 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
600 ListEnumerator *This = (ListEnumerator *)iface;
601 ULONG ref = InterlockedDecrement(&This->ref);
603 TRACE("(%p/%p)\n", iface, This);
605 if (!ref)
607 if (This->pObj) IDispatch_Release((IDispatch *)This->pObj);
608 msi_free(This);
611 return ref;
614 /* IEnumVARIANT methods */
616 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
618 ListEnumerator *This = (ListEnumerator *)iface;
619 ListData *data = private_data(This->pObj);
620 ULONG idx, local;
622 TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched);
624 if (pCeltFetched != NULL)
625 *pCeltFetched = 0;
627 if (rgVar == NULL)
628 return S_FALSE;
630 for (local = 0; local < celt; local++)
631 VariantInit(&rgVar[local]);
633 for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++)
634 VariantCopy(&rgVar[local], &data->pVars[idx]);
636 if (pCeltFetched != NULL)
637 *pCeltFetched = local;
638 This->ulPos = idx;
640 return (local < celt) ? S_FALSE : S_OK;
643 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
645 ListEnumerator *This = (ListEnumerator *)iface;
646 ListData *data = private_data(This->pObj);
648 TRACE("(%p,%uld)\n", iface, celt);
650 This->ulPos += celt;
651 if (This->ulPos >= data->ulCount)
653 This->ulPos = data->ulCount;
654 return S_FALSE;
656 return S_OK;
659 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
661 ListEnumerator *This = (ListEnumerator *)iface;
663 TRACE("(%p)\n", iface);
665 This->ulPos = 0;
666 return S_OK;
669 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
671 ListEnumerator *This = (ListEnumerator *)iface;
672 HRESULT hr;
674 TRACE("(%p,%p)\n", iface, ppEnum);
676 if (ppEnum == NULL)
677 return S_FALSE;
679 *ppEnum = NULL;
680 hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0);
681 if (FAILED(hr))
683 if (*ppEnum)
684 IUnknown_Release(*ppEnum);
685 return hr;
688 return S_OK;
691 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
693 ListEnumerator_QueryInterface,
694 ListEnumerator_AddRef,
695 ListEnumerator_Release,
696 ListEnumerator_Next,
697 ListEnumerator_Skip,
698 ListEnumerator_Reset,
699 ListEnumerator_Clone
703 * Individual Object Invocation Functions
706 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
707 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
708 using DispGetParam/VariantChangeType. */
709 static HRESULT DispGetParam_CopyOnly(
710 DISPPARAMS *pdispparams, /* [in] Parameter list */
711 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
712 VARIANT *pvarResult) /* [out] Destination for resulting variant */
714 /* position is counted backwards */
715 UINT pos;
717 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
718 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
719 if (*position < pdispparams->cArgs) {
720 /* positional arg? */
721 pos = pdispparams->cArgs - *position - 1;
722 } else {
723 /* FIXME: is this how to handle named args? */
724 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
725 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
727 if (pos==pdispparams->cNamedArgs)
728 return DISP_E_PARAMNOTFOUND;
730 *position = pos;
731 return VariantCopyInd(pvarResult,
732 &pdispparams->rgvarg[pos]);
735 static HRESULT WINAPI SummaryInfoImpl_Invoke(
736 AutomationObject* This,
737 DISPID dispIdMember,
738 REFIID riid,
739 LCID lcid,
740 WORD wFlags,
741 DISPPARAMS* pDispParams,
742 VARIANT* pVarResult,
743 EXCEPINFO* pExcepInfo,
744 UINT* puArgErr)
746 UINT ret;
747 VARIANTARG varg0, varg1;
748 FILETIME ft, ftlocal;
749 SYSTEMTIME st;
750 HRESULT hr;
752 VariantInit(&varg0);
753 VariantInit(&varg1);
755 switch (dispIdMember)
757 case DISPID_SUMMARYINFO_PROPERTY:
758 if (wFlags & DISPATCH_PROPERTYGET)
760 UINT type;
761 INT value;
762 DWORD size = 0;
763 DATE date;
764 LPWSTR str;
766 static WCHAR szEmpty[] = {0};
768 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
769 if (FAILED(hr)) return hr;
770 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
771 &ft, szEmpty, &size);
772 if (ret != ERROR_SUCCESS &&
773 ret != ERROR_MORE_DATA)
775 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
776 return DISP_E_EXCEPTION;
779 switch (type)
781 case VT_EMPTY:
782 break;
784 case VT_I2:
785 case VT_I4:
786 V_VT(pVarResult) = VT_I4;
787 V_I4(pVarResult) = value;
788 break;
790 case VT_LPSTR:
791 if (!(str = msi_alloc(++size * sizeof(WCHAR))))
792 ERR("Out of memory\n");
793 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
794 NULL, str, &size)) != ERROR_SUCCESS)
795 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
796 else
798 V_VT(pVarResult) = VT_BSTR;
799 V_BSTR(pVarResult) = SysAllocString(str);
801 msi_free(str);
802 break;
804 case VT_FILETIME:
805 FileTimeToLocalFileTime(&ft, &ftlocal);
806 FileTimeToSystemTime(&ftlocal, &st);
807 SystemTimeToVariantTime(&st, &date);
809 V_VT(pVarResult) = VT_DATE;
810 V_DATE(pVarResult) = date;
811 break;
813 default:
814 ERR("Unhandled variant type %d\n", type);
817 else if (wFlags & DISPATCH_PROPERTYPUT)
819 UINT posValue = DISPID_PROPERTYPUT;
821 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
822 if (FAILED(hr)) return hr;
823 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
824 if (FAILED(hr))
826 *puArgErr = posValue;
827 return hr;
830 switch (V_VT(&varg1))
832 case VT_I2:
833 case VT_I4:
834 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
835 break;
837 case VT_DATE:
838 VariantTimeToSystemTime(V_DATE(&varg1), &st);
839 SystemTimeToFileTime(&st, &ftlocal);
840 LocalFileTimeToFileTime(&ftlocal, &ft);
841 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
842 break;
844 case VT_BSTR:
845 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
846 break;
848 default:
849 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
850 VariantClear(&varg1);
851 return DISP_E_EXCEPTION;
854 if (ret != ERROR_SUCCESS)
856 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
857 return DISP_E_EXCEPTION;
860 else return DISP_E_MEMBERNOTFOUND;
861 break;
863 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
864 if (wFlags & DISPATCH_PROPERTYGET) {
865 UINT count;
866 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
867 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
868 else
870 V_VT(pVarResult) = VT_I4;
871 V_I4(pVarResult) = count;
874 else return DISP_E_MEMBERNOTFOUND;
875 break;
877 default:
878 return DISP_E_MEMBERNOTFOUND;
881 VariantClear(&varg1);
882 VariantClear(&varg0);
884 return S_OK;
887 static HRESULT WINAPI RecordImpl_Invoke(
888 AutomationObject* This,
889 DISPID dispIdMember,
890 REFIID riid,
891 LCID lcid,
892 WORD wFlags,
893 DISPPARAMS* pDispParams,
894 VARIANT* pVarResult,
895 EXCEPINFO* pExcepInfo,
896 UINT* puArgErr)
898 WCHAR *szString;
899 DWORD dwLen;
900 UINT ret;
901 VARIANTARG varg0, varg1;
902 HRESULT hr;
904 VariantInit(&varg0);
905 VariantInit(&varg1);
907 switch (dispIdMember)
909 case DISPID_RECORD_FIELDCOUNT:
910 if (wFlags & DISPATCH_PROPERTYGET) {
911 V_VT(pVarResult) = VT_I4;
912 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
914 else return DISP_E_MEMBERNOTFOUND;
915 break;
917 case DISPID_RECORD_STRINGDATA:
918 if (wFlags & DISPATCH_PROPERTYGET) {
919 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
920 if (FAILED(hr)) return hr;
921 V_VT(pVarResult) = VT_BSTR;
922 V_BSTR(pVarResult) = NULL;
923 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
925 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
926 ERR("Out of memory\n");
927 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
928 V_BSTR(pVarResult) = SysAllocString(szString);
929 msi_free(szString);
931 if (ret != ERROR_SUCCESS)
932 ERR("MsiRecordGetString returned %d\n", ret);
933 } else if (wFlags & DISPATCH_PROPERTYPUT) {
934 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
935 if (FAILED(hr)) return hr;
936 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
937 if (FAILED(hr)) return hr;
938 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
940 VariantClear(&varg1);
941 ERR("MsiRecordSetString returned %d\n", ret);
942 return DISP_E_EXCEPTION;
945 else return DISP_E_MEMBERNOTFOUND;
946 break;
948 case DISPID_RECORD_INTEGERDATA:
949 if (wFlags & DISPATCH_PROPERTYGET) {
950 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
951 if (FAILED(hr)) return hr;
952 V_VT(pVarResult) = VT_I4;
953 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
954 } else if (wFlags & DISPATCH_PROPERTYPUT) {
955 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
956 if (FAILED(hr)) return hr;
957 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
958 if (FAILED(hr)) return hr;
959 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
961 ERR("MsiRecordSetInteger returned %d\n", ret);
962 return DISP_E_EXCEPTION;
965 else return DISP_E_MEMBERNOTFOUND;
966 break;
968 default:
969 return DISP_E_MEMBERNOTFOUND;
972 VariantClear(&varg1);
973 VariantClear(&varg0);
975 return S_OK;
978 static HRESULT WINAPI ListImpl_Invoke(
979 AutomationObject* This,
980 DISPID dispIdMember,
981 REFIID riid,
982 LCID lcid,
983 WORD wFlags,
984 DISPPARAMS* pDispParams,
985 VARIANT* pVarResult,
986 EXCEPINFO* pExcepInfo,
987 UINT* puArgErr)
989 ListData *data = private_data(This);
990 HRESULT hr;
991 VARIANTARG varg0;
992 IUnknown *pUnk = NULL;
994 VariantInit(&varg0);
996 switch (dispIdMember)
998 case DISPID_LIST__NEWENUM:
999 if (wFlags & DISPATCH_METHOD) {
1000 V_VT(pVarResult) = VT_UNKNOWN;
1001 if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0)))
1002 V_UNKNOWN(pVarResult) = pUnk;
1003 else
1004 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
1006 else return DISP_E_MEMBERNOTFOUND;
1007 break;
1009 case DISPID_LIST_ITEM:
1010 if (wFlags & DISPATCH_PROPERTYGET) {
1011 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1012 if (FAILED(hr)) return hr;
1013 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount)
1014 return DISP_E_BADINDEX;
1015 VariantCopy(pVarResult, &data->pVars[V_I4(&varg0)]);
1017 else return DISP_E_MEMBERNOTFOUND;
1018 break;
1020 case DISPID_LIST_COUNT:
1021 if (wFlags & DISPATCH_PROPERTYGET) {
1022 V_VT(pVarResult) = VT_I4;
1023 V_I4(pVarResult) = data->ulCount;
1025 else return DISP_E_MEMBERNOTFOUND;
1026 break;
1028 default:
1029 return DISP_E_MEMBERNOTFOUND;
1032 VariantClear(&varg0);
1034 return S_OK;
1037 static void WINAPI ListImpl_Free(AutomationObject *This)
1039 ListData *data = private_data(This);
1040 ULONG idx;
1042 for (idx=0; idx<data->ulCount; idx++)
1043 VariantClear(&data->pVars[idx]);
1044 msi_free(data->pVars);
1047 static HRESULT WINAPI ViewImpl_Invoke(
1048 AutomationObject* This,
1049 DISPID dispIdMember,
1050 REFIID riid,
1051 LCID lcid,
1052 WORD wFlags,
1053 DISPPARAMS* pDispParams,
1054 VARIANT* pVarResult,
1055 EXCEPINFO* pExcepInfo,
1056 UINT* puArgErr)
1058 MSIHANDLE msiHandle;
1059 IDispatch *pDispatch = NULL;
1060 UINT ret;
1061 VARIANTARG varg0, varg1;
1062 HRESULT hr;
1064 VariantInit(&varg0);
1065 VariantInit(&varg1);
1067 switch (dispIdMember)
1069 case DISPID_VIEW_EXECUTE:
1070 if (wFlags & DISPATCH_METHOD)
1072 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1073 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1074 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1075 else
1076 MsiViewExecute(This->msiHandle, 0);
1078 else return DISP_E_MEMBERNOTFOUND;
1079 break;
1081 case DISPID_VIEW_FETCH:
1082 if (wFlags & DISPATCH_METHOD)
1084 V_VT(pVarResult) = VT_DISPATCH;
1085 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1087 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1088 V_DISPATCH(pVarResult) = pDispatch;
1089 else
1090 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1092 else if (ret == ERROR_NO_MORE_ITEMS)
1093 V_DISPATCH(pVarResult) = NULL;
1094 else
1096 ERR("MsiViewFetch returned %d\n", ret);
1097 return DISP_E_EXCEPTION;
1100 else return DISP_E_MEMBERNOTFOUND;
1101 break;
1103 case DISPID_VIEW_MODIFY:
1104 if (wFlags & DISPATCH_METHOD)
1106 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1107 if (FAILED(hr)) return hr;
1108 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1109 if (FAILED(hr)) return hr;
1110 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1111 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1113 VariantClear(&varg1);
1114 ERR("MsiViewModify returned %d\n", ret);
1115 return DISP_E_EXCEPTION;
1118 else return DISP_E_MEMBERNOTFOUND;
1119 break;
1121 case DISPID_VIEW_CLOSE:
1122 if (wFlags & DISPATCH_METHOD)
1124 MsiViewClose(This->msiHandle);
1126 else return DISP_E_MEMBERNOTFOUND;
1127 break;
1129 default:
1130 return DISP_E_MEMBERNOTFOUND;
1133 VariantClear(&varg1);
1134 VariantClear(&varg0);
1136 return S_OK;
1139 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
1140 DISPPARAMS* pDispParams,
1141 VARIANT* pVarResult,
1142 EXCEPINFO* pExcepInfo,
1143 UINT* puArgErr)
1145 if (!(wFlags & DISPATCH_METHOD))
1146 return DISP_E_MEMBERNOTFOUND;
1148 FIXME("\n");
1150 VariantInit(pVarResult);
1151 return S_OK;
1154 static HRESULT WINAPI DatabaseImpl_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)
1165 MSIHANDLE msiHandle;
1166 IDispatch *pDispatch = NULL;
1167 UINT ret;
1168 VARIANTARG varg0, varg1;
1169 HRESULT hr;
1171 VariantInit(&varg0);
1172 VariantInit(&varg1);
1174 switch (dispIdMember)
1176 case DISPID_DATABASE_SUMMARYINFORMATION:
1177 if (wFlags & DISPATCH_PROPERTYGET)
1179 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1180 if (FAILED(hr))
1181 V_I4(&varg0) = 0;
1183 V_VT(pVarResult) = VT_DISPATCH;
1184 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1186 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0);
1187 if (SUCCEEDED(hr))
1188 V_DISPATCH(pVarResult) = pDispatch;
1189 else
1190 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1192 else
1194 ERR("MsiGetSummaryInformation returned %d\n", ret);
1195 return DISP_E_EXCEPTION;
1198 else return DISP_E_MEMBERNOTFOUND;
1199 break;
1201 case DISPID_DATABASE_OPENVIEW:
1202 if (wFlags & DISPATCH_METHOD)
1204 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1205 if (FAILED(hr)) return hr;
1206 V_VT(pVarResult) = VT_DISPATCH;
1207 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1209 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1210 V_DISPATCH(pVarResult) = pDispatch;
1211 else
1212 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1214 else
1216 VariantClear(&varg0);
1217 ERR("MsiDatabaseOpenView returned %d\n", ret);
1218 return DISP_E_EXCEPTION;
1221 else return DISP_E_MEMBERNOTFOUND;
1222 break;
1224 case DISPID_INSTALLER_LASTERRORRECORD:
1225 return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
1226 pVarResult, pExcepInfo,
1227 puArgErr);
1229 default:
1230 return DISP_E_MEMBERNOTFOUND;
1233 VariantClear(&varg1);
1234 VariantClear(&varg0);
1236 return S_OK;
1239 static HRESULT WINAPI SessionImpl_Invoke(
1240 AutomationObject* This,
1241 DISPID dispIdMember,
1242 REFIID riid,
1243 LCID lcid,
1244 WORD wFlags,
1245 DISPPARAMS* pDispParams,
1246 VARIANT* pVarResult,
1247 EXCEPINFO* pExcepInfo,
1248 UINT* puArgErr)
1250 SessionData *data = private_data(This);
1251 WCHAR *szString;
1252 DWORD dwLen;
1253 IDispatch *pDispatch = NULL;
1254 MSIHANDLE msiHandle;
1255 LANGID langId;
1256 UINT ret;
1257 INSTALLSTATE iInstalled, iAction;
1258 VARIANTARG varg0, varg1;
1259 HRESULT hr;
1261 VariantInit(&varg0);
1262 VariantInit(&varg1);
1264 switch (dispIdMember)
1266 case DISPID_SESSION_INSTALLER:
1267 if (wFlags & DISPATCH_PROPERTYGET) {
1268 V_VT(pVarResult) = VT_DISPATCH;
1269 IDispatch_AddRef(data->pInstaller);
1270 V_DISPATCH(pVarResult) = data->pInstaller;
1272 else return DISP_E_MEMBERNOTFOUND;
1273 break;
1275 case DISPID_SESSION_PROPERTY:
1276 if (wFlags & DISPATCH_PROPERTYGET) {
1277 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1278 if (FAILED(hr)) return hr;
1279 V_VT(pVarResult) = VT_BSTR;
1280 V_BSTR(pVarResult) = NULL;
1281 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1283 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1284 ERR("Out of memory\n");
1285 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1286 V_BSTR(pVarResult) = SysAllocString(szString);
1287 msi_free(szString);
1289 if (ret != ERROR_SUCCESS)
1290 ERR("MsiGetProperty returned %d\n", ret);
1291 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1292 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1293 if (FAILED(hr)) return hr;
1294 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1295 if (FAILED(hr)) {
1296 VariantClear(&varg0);
1297 return hr;
1299 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1301 VariantClear(&varg0);
1302 VariantClear(&varg1);
1303 ERR("MsiSetProperty returned %d\n", ret);
1304 return DISP_E_EXCEPTION;
1307 else return DISP_E_MEMBERNOTFOUND;
1308 break;
1310 case DISPID_SESSION_LANGUAGE:
1311 if (wFlags & DISPATCH_PROPERTYGET) {
1312 langId = MsiGetLanguage(This->msiHandle);
1313 V_VT(pVarResult) = VT_I4;
1314 V_I4(pVarResult) = langId;
1316 else return DISP_E_MEMBERNOTFOUND;
1317 break;
1319 case DISPID_SESSION_MODE:
1320 if (wFlags & DISPATCH_PROPERTYGET) {
1321 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1322 if (FAILED(hr)) return hr;
1323 V_VT(pVarResult) = VT_BOOL;
1324 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1325 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1326 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1327 if (FAILED(hr)) return hr;
1328 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1329 if (FAILED(hr)) return hr;
1330 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1332 ERR("MsiSetMode returned %d\n", ret);
1333 return DISP_E_EXCEPTION;
1336 else return DISP_E_MEMBERNOTFOUND;
1337 break;
1339 case DISPID_SESSION_DATABASE:
1340 if (wFlags & DISPATCH_PROPERTYGET) {
1341 V_VT(pVarResult) = VT_DISPATCH;
1342 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1344 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1345 V_DISPATCH(pVarResult) = pDispatch;
1346 else
1347 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1349 else
1351 ERR("MsiGetActiveDatabase failed\n");
1352 return DISP_E_EXCEPTION;
1355 else return DISP_E_MEMBERNOTFOUND;
1356 break;
1358 case DISPID_SESSION_DOACTION:
1359 if (wFlags & DISPATCH_METHOD) {
1360 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1361 if (FAILED(hr)) return hr;
1362 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1363 V_VT(pVarResult) = VT_I4;
1364 switch (ret)
1366 case ERROR_FUNCTION_NOT_CALLED:
1367 V_I4(pVarResult) = msiDoActionStatusNoAction;
1368 break;
1369 case ERROR_SUCCESS:
1370 V_I4(pVarResult) = msiDoActionStatusSuccess;
1371 break;
1372 case ERROR_INSTALL_USEREXIT:
1373 V_I4(pVarResult) = msiDoActionStatusUserExit;
1374 break;
1375 case ERROR_INSTALL_FAILURE:
1376 V_I4(pVarResult) = msiDoActionStatusFailure;
1377 break;
1378 case ERROR_INSTALL_SUSPEND:
1379 V_I4(pVarResult) = msiDoActionStatusSuspend;
1380 break;
1381 case ERROR_MORE_DATA:
1382 V_I4(pVarResult) = msiDoActionStatusFinished;
1383 break;
1384 case ERROR_INVALID_HANDLE_STATE:
1385 V_I4(pVarResult) = msiDoActionStatusWrongState;
1386 break;
1387 case ERROR_INVALID_DATA:
1388 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1389 break;
1390 default:
1391 VariantClear(&varg0);
1392 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1393 return DISP_E_EXCEPTION;
1396 else return DISP_E_MEMBERNOTFOUND;
1397 break;
1399 case DISPID_SESSION_EVALUATECONDITION:
1400 if (wFlags & DISPATCH_METHOD) {
1401 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1402 if (FAILED(hr)) return hr;
1403 V_VT(pVarResult) = VT_I4;
1404 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1406 else return DISP_E_MEMBERNOTFOUND;
1407 break;
1409 case DISPID_SESSION_MESSAGE:
1410 if(!(wFlags & DISPATCH_METHOD))
1411 return DISP_E_MEMBERNOTFOUND;
1413 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1414 if (FAILED(hr)) return hr;
1415 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1416 if (FAILED(hr)) return hr;
1418 V_VT(pVarResult) = VT_I4;
1419 V_I4(pVarResult) =
1420 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
1421 break;
1423 case DISPID_SESSION_SETINSTALLLEVEL:
1424 if (wFlags & DISPATCH_METHOD) {
1425 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1426 if (FAILED(hr)) return hr;
1427 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1429 ERR("MsiSetInstallLevel returned %d\n", ret);
1430 return DISP_E_EXCEPTION;
1433 else return DISP_E_MEMBERNOTFOUND;
1434 break;
1436 case DISPID_SESSION_FEATURECURRENTSTATE:
1437 if (wFlags & DISPATCH_PROPERTYGET) {
1438 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1439 if (FAILED(hr)) return hr;
1440 V_VT(pVarResult) = VT_I4;
1441 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1442 V_I4(pVarResult) = iInstalled;
1443 else
1445 ERR("MsiGetFeatureState returned %d\n", ret);
1446 V_I4(pVarResult) = msiInstallStateUnknown;
1449 else return DISP_E_MEMBERNOTFOUND;
1450 break;
1452 case DISPID_SESSION_FEATUREREQUESTSTATE:
1453 if (wFlags & DISPATCH_PROPERTYGET) {
1454 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1455 if (FAILED(hr)) return hr;
1456 V_VT(pVarResult) = VT_I4;
1457 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1458 V_I4(pVarResult) = iAction;
1459 else
1461 ERR("MsiGetFeatureState returned %d\n", ret);
1462 V_I4(pVarResult) = msiInstallStateUnknown;
1464 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1465 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1466 if (FAILED(hr)) return hr;
1467 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1468 if (FAILED(hr)) {
1469 VariantClear(&varg0);
1470 return hr;
1472 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1474 VariantClear(&varg0);
1475 ERR("MsiSetFeatureState returned %d\n", ret);
1476 return DISP_E_EXCEPTION;
1479 else return DISP_E_MEMBERNOTFOUND;
1480 break;
1482 default:
1483 return DISP_E_MEMBERNOTFOUND;
1486 VariantClear(&varg1);
1487 VariantClear(&varg0);
1489 return S_OK;
1492 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1493 * registry value type. Used by Installer::RegistryValue. */
1494 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1496 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1497 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1498 WCHAR *szString = (WCHAR *)lpData;
1499 LPWSTR szNewString = NULL;
1500 DWORD dwNewSize = 0;
1501 int idx;
1503 switch (dwType)
1505 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1506 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1507 idx = (dwSize/sizeof(WCHAR))-1;
1508 while (idx >= 0 && !szString[idx]) idx--;
1509 for (; idx >= 0; idx--)
1510 if (!szString[idx]) szString[idx] = '\n';
1511 case REG_SZ:
1512 V_VT(pVarResult) = VT_BSTR;
1513 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1514 break;
1516 case REG_EXPAND_SZ:
1517 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1518 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1519 else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1520 ERR("Out of memory\n");
1521 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1522 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1523 else
1525 V_VT(pVarResult) = VT_BSTR;
1526 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1528 msi_free(szNewString);
1529 break;
1531 case REG_DWORD:
1532 V_VT(pVarResult) = VT_I4;
1533 V_I4(pVarResult) = *((DWORD *)lpData);
1534 break;
1536 case REG_QWORD:
1537 V_VT(pVarResult) = VT_BSTR;
1538 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1539 break;
1541 case REG_BINARY:
1542 V_VT(pVarResult) = VT_BSTR;
1543 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1544 break;
1546 case REG_NONE:
1547 V_VT(pVarResult) = VT_EMPTY;
1548 break;
1550 default:
1551 FIXME("Unhandled registry value type %d\n", dwType);
1555 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1556 DISPPARAMS* pDispParams,
1557 VARIANT* pVarResult,
1558 EXCEPINFO* pExcepInfo,
1559 UINT* puArgErr)
1561 HRESULT hr;
1562 VARIANTARG varg0;
1563 MSIHANDLE hrec;
1564 IDispatch* dispatch;
1566 if (!(wFlags & DISPATCH_METHOD))
1567 return DISP_E_MEMBERNOTFOUND;
1569 VariantInit(&varg0);
1570 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1571 if (FAILED(hr))
1572 return hr;
1574 V_VT(pVarResult) = VT_DISPATCH;
1576 hrec = MsiCreateRecord(V_I4(&varg0));
1577 if (!hrec)
1578 return DISP_E_EXCEPTION;
1580 hr = create_automation_object(hrec, NULL, (LPVOID*)&dispatch,
1581 &DIID_Record, RecordImpl_Invoke, NULL, 0);
1582 if (SUCCEEDED(hr))
1583 V_DISPATCH(pVarResult) = dispatch;
1585 return hr;
1588 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1589 WORD wFlags,
1590 DISPPARAMS* pDispParams,
1591 VARIANT* pVarResult,
1592 EXCEPINFO* pExcepInfo,
1593 UINT* puArgErr)
1595 UINT ret;
1596 HRESULT hr;
1597 MSIHANDLE hpkg;
1598 IDispatch* dispatch;
1599 VARIANTARG varg0, varg1;
1601 if (!(wFlags & DISPATCH_METHOD))
1602 return DISP_E_MEMBERNOTFOUND;
1604 if (pDispParams->cArgs == 0)
1605 return DISP_E_TYPEMISMATCH;
1607 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1608 return DISP_E_TYPEMISMATCH;
1610 VariantInit(&varg0);
1611 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1612 if (FAILED(hr))
1613 return hr;
1615 VariantInit(&varg1);
1616 if (pDispParams->cArgs == 2)
1618 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1619 if (FAILED(hr))
1620 goto done;
1622 else
1624 V_VT(&varg1) = VT_I4;
1625 V_I4(&varg1) = 0;
1628 V_VT(pVarResult) = VT_DISPATCH;
1630 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1631 if (ret != ERROR_SUCCESS)
1633 hr = DISP_E_EXCEPTION;
1634 goto done;
1637 hr = create_session(hpkg, (IDispatch *)This, &dispatch);
1638 if (SUCCEEDED(hr))
1639 V_DISPATCH(pVarResult) = dispatch;
1641 done:
1642 VariantClear(&varg0);
1643 VariantClear(&varg1);
1644 return hr;
1647 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1648 DISPPARAMS* pDispParams,
1649 VARIANT* pVarResult,
1650 EXCEPINFO* pExcepInfo,
1651 UINT* puArgErr)
1653 HRESULT hr;
1654 VARIANTARG varg0;
1656 if (!(wFlags & DISPATCH_METHOD))
1657 return DISP_E_MEMBERNOTFOUND;
1659 VariantInit(&varg0);
1660 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1661 if (FAILED(hr))
1662 return hr;
1664 FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1666 VariantInit(pVarResult);
1668 VariantClear(&varg0);
1669 return S_OK;
1672 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1673 DISPPARAMS* pDispParams,
1674 VARIANT* pVarResult,
1675 EXCEPINFO* pExcepInfo,
1676 UINT* puArgErr)
1678 UINT ret;
1679 HRESULT hr;
1680 MSIHANDLE hdb;
1681 IDispatch* dispatch;
1682 VARIANTARG varg0, varg1;
1684 if (!(wFlags & DISPATCH_METHOD))
1685 return DISP_E_MEMBERNOTFOUND;
1687 VariantInit(&varg0);
1688 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1689 if (FAILED(hr))
1690 return hr;
1692 VariantInit(&varg1);
1693 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1694 if (FAILED(hr))
1695 goto done;
1697 V_VT(pVarResult) = VT_DISPATCH;
1699 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1700 if (ret != ERROR_SUCCESS)
1702 hr = DISP_E_EXCEPTION;
1703 goto done;
1706 hr = create_automation_object(hdb, NULL, (LPVOID *)&dispatch,
1707 &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1708 if (SUCCEEDED(hr))
1709 V_DISPATCH(pVarResult) = dispatch;
1711 done:
1712 VariantClear(&varg0);
1713 VariantClear(&varg1);
1714 return hr;
1717 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1718 DISPPARAMS* pDispParams,
1719 VARIANT* pVarResult,
1720 EXCEPINFO* pExcepInfo,
1721 UINT* puArgErr)
1723 if (!(wFlags & DISPATCH_METHOD))
1724 return DISP_E_MEMBERNOTFOUND;
1726 FIXME("\n");
1728 VariantInit(pVarResult);
1729 return S_OK;
1732 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1733 DISPPARAMS* pDispParams,
1734 VARIANT* pVarResult,
1735 EXCEPINFO* pExcepInfo,
1736 UINT* puArgErr)
1738 HRESULT hr;
1739 VARIANTARG varg0;
1740 INSTALLUILEVEL ui;
1742 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1743 return DISP_E_MEMBERNOTFOUND;
1745 if (wFlags & DISPATCH_PROPERTYPUT)
1747 VariantInit(&varg0);
1748 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1749 if (FAILED(hr))
1750 return hr;
1752 ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1753 if (ui == INSTALLUILEVEL_NOCHANGE)
1754 return DISP_E_EXCEPTION;
1756 else if (wFlags & DISPATCH_PROPERTYGET)
1758 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1759 if (ui == INSTALLUILEVEL_NOCHANGE)
1760 return DISP_E_EXCEPTION;
1762 V_VT(pVarResult) = VT_I4;
1763 V_I4(pVarResult) = ui;
1766 return S_OK;
1769 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1770 DISPPARAMS* pDispParams,
1771 VARIANT* pVarResult,
1772 EXCEPINFO* pExcepInfo,
1773 UINT* puArgErr)
1775 if (!(wFlags & DISPATCH_METHOD))
1776 return DISP_E_MEMBERNOTFOUND;
1778 FIXME("\n");
1780 VariantInit(pVarResult);
1781 return S_OK;
1784 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1785 DISPPARAMS* pDispParams,
1786 VARIANT* pVarResult,
1787 EXCEPINFO* pExcepInfo,
1788 UINT* puArgErr)
1790 UINT ret;
1791 HRESULT hr;
1792 VARIANTARG varg0, varg1;
1794 if (!(wFlags & DISPATCH_METHOD))
1795 return DISP_E_MEMBERNOTFOUND;
1797 VariantInit(&varg0);
1798 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1799 if (FAILED(hr))
1800 return hr;
1802 VariantInit(&varg1);
1803 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1804 if (FAILED(hr))
1805 goto done;
1807 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1808 if (ret != ERROR_SUCCESS)
1810 hr = DISP_E_EXCEPTION;
1811 goto done;
1814 done:
1815 VariantClear(&varg0);
1816 VariantClear(&varg1);
1817 return hr;
1820 static HRESULT InstallerImpl_Version(WORD wFlags,
1821 VARIANT* pVarResult,
1822 EXCEPINFO* pExcepInfo,
1823 UINT* puArgErr)
1825 HRESULT hr;
1826 DLLVERSIONINFO verinfo;
1827 WCHAR version[MAX_PATH];
1829 static const WCHAR format[] = {
1830 '%','d','.','%','d','.','%','d','.','%','d',0};
1832 if (!(wFlags & DISPATCH_PROPERTYGET))
1833 return DISP_E_MEMBERNOTFOUND;
1835 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1836 hr = DllGetVersion(&verinfo);
1837 if (FAILED(hr))
1838 return hr;
1840 sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1841 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1843 V_VT(pVarResult) = VT_BSTR;
1844 V_BSTR(pVarResult) = SysAllocString(version);
1845 return S_OK;
1848 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1849 DISPPARAMS* pDispParams,
1850 VARIANT* pVarResult,
1851 EXCEPINFO* pExcepInfo,
1852 UINT* puArgErr)
1854 if (!(wFlags & DISPATCH_METHOD))
1855 return DISP_E_MEMBERNOTFOUND;
1857 FIXME("\n");
1859 VariantInit(pVarResult);
1860 return S_OK;
1863 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1864 DISPPARAMS* pDispParams,
1865 VARIANT* pVarResult,
1866 EXCEPINFO* pExcepInfo,
1867 UINT* puArgErr)
1869 UINT ret;
1870 HKEY hkey = NULL;
1871 HRESULT hr;
1872 UINT posValue;
1873 DWORD type, size;
1874 LPWSTR szString = NULL;
1875 VARIANTARG varg0, varg1, varg2;
1877 if (!(wFlags & DISPATCH_METHOD))
1878 return DISP_E_MEMBERNOTFOUND;
1880 VariantInit(&varg0);
1881 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1882 if (FAILED(hr))
1883 return hr;
1885 VariantInit(&varg1);
1886 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1887 if (FAILED(hr))
1888 goto done;
1890 /* Save valuePos so we can save puArgErr if we are unable to do our type
1891 * conversions.
1893 posValue = 2;
1894 VariantInit(&varg2);
1895 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1896 if (FAILED(hr))
1897 goto done;
1899 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
1900 V_I4(&varg0) <= REG_INDEX_DYN_DATA)
1902 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
1905 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1907 /* Only VT_EMPTY case can do anything if the key doesn't exist. */
1908 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
1910 hr = DISP_E_BADINDEX;
1911 goto done;
1914 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1915 switch (V_VT(&varg2))
1917 /* Return VT_BOOL clarifying whether registry key exists or not. */
1918 case VT_EMPTY:
1919 V_VT(pVarResult) = VT_BOOL;
1920 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1921 break;
1923 /* Return the value of specified key if it exists. */
1924 case VT_BSTR:
1925 ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
1926 NULL, NULL, NULL, &size);
1927 if (ret != ERROR_SUCCESS)
1929 hr = DISP_E_BADINDEX;
1930 goto done;
1933 szString = msi_alloc(size);
1934 if (!szString)
1936 hr = E_OUTOFMEMORY;
1937 goto done;
1940 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
1941 &type, (LPBYTE)szString, &size);
1942 if (ret != ERROR_SUCCESS)
1944 msi_free(szString);
1945 hr = DISP_E_BADINDEX;
1946 goto done;
1949 variant_from_registry_value(pVarResult, type,
1950 (LPBYTE)szString, size);
1951 msi_free(szString);
1952 break;
1954 /* Try to make it into VT_I4, can use VariantChangeType for this. */
1955 default:
1956 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1957 if (FAILED(hr))
1959 if (hr == DISP_E_TYPEMISMATCH)
1960 *puArgErr = posValue;
1962 goto done;
1965 /* Retrieve class name or maximum value name or subkey name size. */
1966 if (!V_I4(&varg2))
1967 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
1968 NULL, NULL, NULL, NULL, NULL, NULL);
1969 else if (V_I4(&varg2) > 0)
1970 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
1971 NULL, NULL, &size, NULL, NULL, NULL);
1972 else /* V_I4(&varg2) < 0 */
1973 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
1974 NULL, NULL, NULL, NULL, NULL, NULL);
1976 if (ret != ERROR_SUCCESS)
1977 goto done;
1979 szString = msi_alloc(++size * sizeof(WCHAR));
1980 if (!szString)
1982 hr = E_OUTOFMEMORY;
1983 goto done;
1986 if (!V_I4(&varg2))
1987 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
1988 NULL, NULL, NULL, NULL, NULL, NULL);
1989 else if (V_I4(&varg2) > 0)
1990 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
1991 &size, 0, 0, NULL, NULL);
1992 else /* V_I4(&varg2) < 0 */
1993 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
1995 if (ret == ERROR_SUCCESS)
1997 V_VT(pVarResult) = VT_BSTR;
1998 V_BSTR(pVarResult) = SysAllocString(szString);
2001 msi_free(szString);
2004 done:
2005 VariantClear(&varg0);
2006 VariantClear(&varg1);
2007 VariantClear(&varg2);
2008 RegCloseKey(hkey);
2009 return hr;
2012 static HRESULT InstallerImpl_Environment(WORD wFlags,
2013 DISPPARAMS* pDispParams,
2014 VARIANT* pVarResult,
2015 EXCEPINFO* pExcepInfo,
2016 UINT* puArgErr)
2018 if (!(wFlags & DISPATCH_METHOD))
2019 return DISP_E_MEMBERNOTFOUND;
2021 FIXME("\n");
2023 VariantInit(pVarResult);
2024 return S_OK;
2027 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2028 DISPPARAMS* pDispParams,
2029 VARIANT* pVarResult,
2030 EXCEPINFO* pExcepInfo,
2031 UINT* puArgErr)
2033 if (!(wFlags & DISPATCH_METHOD))
2034 return DISP_E_MEMBERNOTFOUND;
2036 FIXME("\n");
2038 VariantInit(pVarResult);
2039 return S_OK;
2042 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2043 DISPPARAMS* pDispParams,
2044 VARIANT* pVarResult,
2045 EXCEPINFO* pExcepInfo,
2046 UINT* puArgErr)
2048 if (!(wFlags & DISPATCH_METHOD))
2049 return DISP_E_MEMBERNOTFOUND;
2051 FIXME("\n");
2053 VariantInit(pVarResult);
2054 return S_OK;
2057 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2058 DISPPARAMS* pDispParams,
2059 VARIANT* pVarResult,
2060 EXCEPINFO* pExcepInfo,
2061 UINT* puArgErr)
2063 if (!(wFlags & DISPATCH_METHOD))
2064 return DISP_E_MEMBERNOTFOUND;
2066 FIXME("\n");
2068 VariantInit(pVarResult);
2069 return S_OK;
2072 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2073 DISPPARAMS* pDispParams,
2074 VARIANT* pVarResult,
2075 EXCEPINFO* pExcepInfo,
2076 UINT* puArgErr)
2078 HRESULT hr;
2079 VARIANTARG varg0;
2081 if (!(wFlags & DISPATCH_PROPERTYGET))
2082 return DISP_E_MEMBERNOTFOUND;
2084 VariantInit(&varg0);
2085 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2086 if (FAILED(hr))
2087 return hr;
2089 V_VT(pVarResult) = VT_I4;
2090 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2092 VariantClear(&varg0);
2093 return S_OK;
2096 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2097 DISPPARAMS* pDispParams,
2098 VARIANT* pVarResult,
2099 EXCEPINFO* pExcepInfo,
2100 UINT* puArgErr)
2102 UINT ret;
2103 HRESULT hr;
2104 DWORD size;
2105 LPWSTR str = NULL;
2106 VARIANTARG varg0, varg1;
2108 if (!(wFlags & DISPATCH_PROPERTYGET))
2109 return DISP_E_MEMBERNOTFOUND;
2111 VariantInit(&varg0);
2112 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2113 if (FAILED(hr))
2114 return hr;
2116 VariantInit(&varg1);
2117 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2118 if (FAILED(hr))
2119 goto done;
2121 V_VT(pVarResult) = VT_BSTR;
2122 V_BSTR(pVarResult) = NULL;
2124 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2125 if (ret != ERROR_SUCCESS)
2127 hr = DISP_E_EXCEPTION;
2128 goto done;
2131 str = msi_alloc(++size * sizeof(WCHAR));
2132 if (!str)
2134 hr = E_OUTOFMEMORY;
2135 goto done;
2138 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2139 if (ret != ERROR_SUCCESS)
2141 hr = DISP_E_EXCEPTION;
2142 goto done;
2145 V_BSTR(pVarResult) = SysAllocString(str);
2146 hr = S_OK;
2148 done:
2149 msi_free(str);
2150 VariantClear(&varg0);
2151 VariantClear(&varg1);
2152 return hr;
2155 static void cleanup_products(IDispatch* dispatch, ULONG count)
2157 UINT i;
2158 ListData* ldata = private_data((AutomationObject *)dispatch);
2160 for (i = 0; i < count - 1; i++)
2161 VariantClear(&ldata->pVars[i]);
2163 ldata->ulCount = 0;
2164 msi_free(ldata->pVars);
2166 IDispatch_Release(dispatch);
2169 static HRESULT InstallerImpl_Products(WORD wFlags,
2170 DISPPARAMS* pDispParams,
2171 VARIANT* pVarResult,
2172 EXCEPINFO* pExcepInfo,
2173 UINT* puArgErr)
2175 UINT ret;
2176 HRESULT hr;
2177 ULONG idx = 0;
2178 ListData *ldata;
2179 IDispatch *dispatch;
2180 WCHAR product[GUID_SIZE];
2182 if (!(wFlags & DISPATCH_PROPERTYGET))
2183 return DISP_E_MEMBERNOTFOUND;
2185 /* Find number of products. */
2186 while ((ret = MsiEnumProductsW(idx, product)) == ERROR_SUCCESS)
2187 idx++;
2189 if (ret != ERROR_NO_MORE_ITEMS)
2190 return DISP_E_EXCEPTION;
2192 V_VT(pVarResult) = VT_DISPATCH;
2193 hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2194 &DIID_StringList, ListImpl_Invoke,
2195 ListImpl_Free, sizeof(ListData));
2196 if (FAILED(hr))
2197 return hr;
2199 V_DISPATCH(pVarResult) = dispatch;
2201 /* Save product strings. */
2202 ldata = private_data((AutomationObject *)dispatch);
2203 ldata->ulCount = 0;
2204 ldata->pVars = msi_alloc_zero(sizeof(VARIANT) * idx);
2205 if (!ldata->pVars)
2207 IDispatch_Release(dispatch);
2208 return E_OUTOFMEMORY;
2211 ldata->ulCount = idx;
2212 for (idx = 0; idx < ldata->ulCount; idx++)
2214 ret = MsiEnumProductsW(idx, product);
2215 if (ret != ERROR_SUCCESS)
2217 cleanup_products(dispatch, idx - 1);
2218 return DISP_E_EXCEPTION;
2221 VariantInit(&ldata->pVars[idx]);
2222 V_VT(&ldata->pVars[idx]) = VT_BSTR;
2223 V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2226 return S_OK;
2229 static HRESULT InstallerImpl_RelatedProducts(WORD wFlags,
2230 DISPPARAMS* pDispParams,
2231 VARIANT* pVarResult,
2232 EXCEPINFO* pExcepInfo,
2233 UINT* puArgErr)
2235 UINT ret;
2236 ULONG idx;
2237 HRESULT hr;
2238 ListData *ldata;
2239 VARIANTARG varg0;
2240 IDispatch* dispatch;
2241 WCHAR product[GUID_SIZE];
2243 if (!(wFlags & DISPATCH_PROPERTYGET))
2244 return DISP_E_MEMBERNOTFOUND;
2246 VariantInit(&varg0);
2247 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2248 if (FAILED(hr))
2249 return hr;
2251 /* Find number of related products. */
2252 idx = 0;
2255 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2256 if (ret == ERROR_SUCCESS)
2257 idx++;
2258 } while (ret == ERROR_SUCCESS);
2260 if (ret != ERROR_NO_MORE_ITEMS)
2262 hr = DISP_E_EXCEPTION;
2263 goto done;
2266 V_VT(pVarResult) = VT_DISPATCH;
2268 hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2269 &DIID_StringList, ListImpl_Invoke,
2270 ListImpl_Free, sizeof(ListData));
2271 if (FAILED(hr))
2272 goto done;
2274 V_DISPATCH(pVarResult) = dispatch;
2276 /* Save product strings. */
2277 ldata = private_data((AutomationObject *)dispatch);
2278 ldata->pVars = msi_alloc(sizeof(VARIANT) * idx);
2279 if (!ldata->pVars)
2281 IDispatch_Release(dispatch);
2282 hr = E_OUTOFMEMORY;
2283 goto done;
2286 ldata->ulCount = idx;
2287 for (idx = 0; idx < ldata->ulCount; idx++)
2289 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2290 if (ret != ERROR_SUCCESS)
2292 cleanup_products(dispatch, idx - 1);
2293 hr = DISP_E_EXCEPTION;
2294 goto done;
2297 VariantInit(&ldata->pVars[idx]);
2298 V_VT(&ldata->pVars[idx]) = VT_BSTR;
2299 V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2302 hr = S_OK;
2304 done:
2305 VariantClear(&varg0);
2306 return hr;
2309 static HRESULT WINAPI InstallerImpl_Invoke(
2310 AutomationObject* This,
2311 DISPID dispIdMember,
2312 REFIID riid,
2313 LCID lcid,
2314 WORD wFlags,
2315 DISPPARAMS* pDispParams,
2316 VARIANT* pVarResult,
2317 EXCEPINFO* pExcepInfo,
2318 UINT* puArgErr)
2320 switch (dispIdMember)
2322 case DISPID_INSTALLER_CREATERECORD:
2323 return InstallerImpl_CreateRecord(wFlags, pDispParams,
2324 pVarResult, pExcepInfo, puArgErr);
2326 case DISPID_INSTALLER_OPENPACKAGE:
2327 return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2328 pVarResult, pExcepInfo, puArgErr);
2330 case DISPID_INSTALLER_OPENPRODUCT:
2331 return InstallerImpl_OpenProduct(wFlags, pDispParams,
2332 pVarResult, pExcepInfo, puArgErr);
2334 case DISPID_INSTALLER_OPENDATABASE:
2335 return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2336 pVarResult, pExcepInfo, puArgErr);
2338 case DISPID_INSTALLER_SUMMARYINFORMATION:
2339 return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2340 pVarResult, pExcepInfo,
2341 puArgErr);
2343 case DISPID_INSTALLER_UILEVEL:
2344 return InstallerImpl_UILevel(wFlags, pDispParams,
2345 pVarResult, pExcepInfo, puArgErr);
2347 case DISPID_INSTALLER_ENABLELOG:
2348 return InstallerImpl_EnableLog(wFlags, pDispParams,
2349 pVarResult, pExcepInfo, puArgErr);
2351 case DISPID_INSTALLER_INSTALLPRODUCT:
2352 return InstallerImpl_InstallProduct(wFlags, pDispParams,
2353 pVarResult, pExcepInfo,
2354 puArgErr);
2356 case DISPID_INSTALLER_VERSION:
2357 return InstallerImpl_Version(wFlags, pVarResult,
2358 pExcepInfo, puArgErr);
2360 case DISPID_INSTALLER_LASTERRORRECORD:
2361 return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2362 pVarResult, pExcepInfo,
2363 puArgErr);
2365 case DISPID_INSTALLER_REGISTRYVALUE:
2366 return InstallerImpl_RegistryValue(wFlags, pDispParams,
2367 pVarResult, pExcepInfo,
2368 puArgErr);
2370 case DISPID_INSTALLER_ENVIRONMENT:
2371 return InstallerImpl_Environment(wFlags, pDispParams,
2372 pVarResult, pExcepInfo, puArgErr);
2374 case DISPID_INSTALLER_FILEATTRIBUTES:
2375 return InstallerImpl_FileAttributes(wFlags, pDispParams,
2376 pVarResult, pExcepInfo,
2377 puArgErr);
2379 case DISPID_INSTALLER_FILESIZE:
2380 return InstallerImpl_FileSize(wFlags, pDispParams,
2381 pVarResult, pExcepInfo, puArgErr);
2383 case DISPID_INSTALLER_FILEVERSION:
2384 return InstallerImpl_FileVersion(wFlags, pDispParams,
2385 pVarResult, pExcepInfo, puArgErr);
2387 case DISPID_INSTALLER_PRODUCTSTATE:
2388 return InstallerImpl_ProductState(wFlags, pDispParams,
2389 pVarResult, pExcepInfo, puArgErr);
2391 case DISPID_INSTALLER_PRODUCTINFO:
2392 return InstallerImpl_ProductInfo(wFlags, pDispParams,
2393 pVarResult, pExcepInfo, puArgErr);
2395 case DISPID_INSTALLER_PRODUCTS:
2396 return InstallerImpl_Products(wFlags, pDispParams,
2397 pVarResult, pExcepInfo, puArgErr);
2399 case DISPID_INSTALLER_RELATEDPRODUCTS:
2400 return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2401 pVarResult, pExcepInfo,
2402 puArgErr);
2404 default:
2405 return DISP_E_MEMBERNOTFOUND;
2409 /* Wrapper around create_automation_object to create an installer object. */
2410 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
2412 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
2415 /* Wrapper around create_automation_object to create a session object. */
2416 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
2418 HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
2419 if (SUCCEEDED(hr) && pDispatch && *pDispatch)
2420 ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
2421 return hr;