push 96093b2868a8b399dfba4b98166e1ffce49bf2f1
[wine/hacks.git] / dlls / msi / automation.c
blob6b1f6c2b2a2550a9b187ddef1749a5cb4cf59ce8
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 "wine/debug.h"
34 #include "wine/unicode.h"
36 #include "msiserver.h"
37 #include "msiserver_dispids.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
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.
46 typedef interface AutomationObject AutomationObject;
48 interface AutomationObject {
50 * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
52 const IDispatchVtbl *lpVtbl;
53 const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
55 /* Object reference count */
56 LONG ref;
58 /* Clsid for this class and it's appropriate ITypeInfo object */
59 LPCLSID clsid;
60 ITypeInfo *iTypeInfo;
62 /* The MSI handle of the current object */
63 MSIHANDLE msiHandle;
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);
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);
83 * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
86 typedef interface ListEnumerator ListEnumerator;
88 interface ListEnumerator {
89 /* VTables */
90 const IEnumVARIANTVtbl *lpVtbl;
92 /* Object reference count */
93 LONG ref;
95 /* Current position and pointer to AutomationObject that stores actual data */
96 ULONG ulPos;
97 AutomationObject *pObj;
101 * Structures for additional data required by specific automation objects
104 typedef struct {
105 ULONG ulCount;
106 VARIANT *pVars;
107 } ListData;
109 typedef struct {
110 /* The parent Installer object */
111 IDispatch *pInstaller;
112 } SessionData;
114 /* VTables */
115 static const struct IDispatchVtbl AutomationObject_Vtbl;
116 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
117 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl;
119 /* Load type info so we don't have to process GetIDsOfNames */
120 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
122 HRESULT hr;
123 LPTYPELIB pLib = NULL;
124 LPTYPEINFO pInfo = NULL;
125 static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
127 TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
129 /* Load registered type library */
130 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
131 if (FAILED(hr)) {
132 hr = LoadTypeLib(szMsiServer, &pLib);
133 if (FAILED(hr)) {
134 ERR("Could not load msiserver.tlb\n");
135 return hr;
139 /* Get type information for object */
140 hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
141 ITypeLib_Release(pLib);
142 if (FAILED(hr)) {
143 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
144 return hr;
146 *pptinfo = pInfo;
147 return S_OK;
150 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
151 * with the appropriate clsid and invocation function. */
152 HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
153 HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
154 VARIANT*,EXCEPINFO*,UINT*),
155 void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
156 SIZE_T sizetPrivateData)
158 AutomationObject *object;
159 HRESULT hr;
161 TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
163 if( pUnkOuter )
164 return CLASS_E_NOAGGREGATION;
166 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData);
168 /* Set all the VTable references */
169 object->lpVtbl = &AutomationObject_Vtbl;
170 object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
171 object->ref = 1;
173 /* Store data that was passed */
174 object->msiHandle = msiHandle;
175 object->clsid = (LPCLSID)clsid;
176 object->funcInvoke = funcInvoke;
177 object->funcFree = funcFree;
179 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
180 object->iTypeInfo = NULL;
181 hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
182 if (FAILED(hr)) {
183 HeapFree(GetProcessHeap(), 0, object);
184 return hr;
187 *ppObj = object;
189 return S_OK;
192 /* Create a list enumerator, placing the result in the pointer ppObj. */
193 HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos)
195 ListEnumerator *object;
197 TRACE("(%p,%p,%p,%uld)\n", pUnkOuter, ppObj, pObj, ulPos);
199 if( pUnkOuter )
200 return CLASS_E_NOAGGREGATION;
202 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ListEnumerator));
204 /* Set all the VTable references */
205 object->lpVtbl = &ListEnumerator_Vtbl;
206 object->ref = 1;
208 /* Store data that was passed */
209 object->ulPos = ulPos;
210 object->pObj = pObj;
211 if (pObj) IDispatch_AddRef((IDispatch *)pObj);
213 *ppObj = object;
214 return S_OK;
217 /* Macros to get pointer to AutomationObject from the other VTables. */
218 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
220 return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
223 /* Macro to get pointer to private object data */
224 static inline void *private_data( AutomationObject *This )
226 return This + 1;
230 * AutomationObject methods
233 /*** IUnknown methods ***/
234 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
236 AutomationObject *This = (AutomationObject *)iface;
238 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
240 if (ppvObject == NULL)
241 return E_INVALIDARG;
243 *ppvObject = 0;
245 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
246 *ppvObject = This;
247 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
248 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
249 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
250 *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
251 else
253 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
254 return E_NOINTERFACE;
258 * Query Interface always increases the reference count by one when it is
259 * successful
261 IClassFactory_AddRef(iface);
263 return S_OK;
266 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
268 AutomationObject *This = (AutomationObject *)iface;
270 TRACE("(%p/%p)\n", iface, This);
272 return InterlockedIncrement(&This->ref);
275 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
277 AutomationObject *This = (AutomationObject *)iface;
278 ULONG ref = InterlockedDecrement(&This->ref);
280 TRACE("(%p/%p)\n", iface, This);
282 if (!ref)
284 if (This->funcFree) This->funcFree(This);
285 MsiCloseHandle(This->msiHandle);
286 HeapFree(GetProcessHeap(), 0, This);
289 return ref;
292 /*** IDispatch methods ***/
293 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
294 IDispatch* iface,
295 UINT* pctinfo)
297 AutomationObject *This = (AutomationObject *)iface;
299 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
300 *pctinfo = 1;
301 return S_OK;
304 static HRESULT WINAPI AutomationObject_GetTypeInfo(
305 IDispatch* iface,
306 UINT iTInfo,
307 LCID lcid,
308 ITypeInfo** ppTInfo)
310 AutomationObject *This = (AutomationObject *)iface;
311 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
313 ITypeInfo_AddRef(This->iTypeInfo);
314 *ppTInfo = This->iTypeInfo;
315 return S_OK;
318 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
319 IDispatch* iface,
320 REFIID riid,
321 LPOLESTR* rgszNames,
322 UINT cNames,
323 LCID lcid,
324 DISPID* rgDispId)
326 AutomationObject *This = (AutomationObject *)iface;
327 HRESULT hr;
328 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
330 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
331 hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
332 if (hr == DISP_E_UNKNOWNNAME)
334 int idx;
335 for (idx=0; idx<cNames; idx++)
337 if (rgDispId[idx] == DISPID_UNKNOWN)
338 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
341 return hr;
344 /* Maximum number of allowed function parameters+1 */
345 #define MAX_FUNC_PARAMS 20
347 /* Some error checking is done here to simplify individual object function invocation */
348 static HRESULT WINAPI AutomationObject_Invoke(
349 IDispatch* iface,
350 DISPID dispIdMember,
351 REFIID riid,
352 LCID lcid,
353 WORD wFlags,
354 DISPPARAMS* pDispParams,
355 VARIANT* pVarResult,
356 EXCEPINFO* pExcepInfo,
357 UINT* puArgErr)
359 AutomationObject *This = (AutomationObject *)iface;
360 HRESULT hr;
361 unsigned int uArgErr;
362 VARIANT varResultDummy;
363 BSTR bstrName = NULL;
365 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
367 if (!IsEqualIID(riid, &IID_NULL))
369 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
370 return DISP_E_UNKNOWNNAME;
373 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
375 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
376 return DISP_E_PARAMNOTOPTIONAL;
379 /* This simplifies our individual object invocation functions */
380 if (puArgErr == NULL) puArgErr = &uArgErr;
381 if (pVarResult == NULL) pVarResult = &varResultDummy;
383 /* Assume return type is void unless determined otherwise */
384 VariantInit(pVarResult);
386 /* If we are tracing, we want to see the name of the member we are invoking */
387 if (TRACE_ON(msi))
389 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
390 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
393 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
395 if (hr == DISP_E_MEMBERNOTFOUND) {
396 if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
397 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
399 else if (pExcepInfo &&
400 (hr == DISP_E_PARAMNOTFOUND ||
401 hr == DISP_E_EXCEPTION)) {
402 static const WCHAR szComma[] = { ',',0 };
403 static WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
404 WCHAR szExceptionDescription[MAX_PATH];
405 BSTR bstrParamNames[MAX_FUNC_PARAMS];
406 unsigned namesNo, i;
407 BOOL bFirst = TRUE;
409 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
410 MAX_FUNC_PARAMS, &namesNo)))
412 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
414 else
416 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
417 for (i=0; i<namesNo; i++)
419 if (bFirst) bFirst = FALSE;
420 else {
421 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
423 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
424 SysFreeString(bstrParamNames[i]);
427 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
428 pExcepInfo->wCode = 1000;
429 pExcepInfo->bstrSource = szExceptionSource;
430 pExcepInfo->bstrDescription = szExceptionDescription;
431 hr = DISP_E_EXCEPTION;
435 /* Make sure we free the return variant if it is our dummy variant */
436 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
438 /* Free function name if we retrieved it */
439 if (bstrName) SysFreeString(bstrName);
441 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
443 return hr;
446 static const struct IDispatchVtbl AutomationObject_Vtbl =
448 AutomationObject_QueryInterface,
449 AutomationObject_AddRef,
450 AutomationObject_Release,
451 AutomationObject_GetTypeInfoCount,
452 AutomationObject_GetTypeInfo,
453 AutomationObject_GetIDsOfNames,
454 AutomationObject_Invoke
458 * IProvideMultipleClassInfo methods
461 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
462 IProvideMultipleClassInfo* iface,
463 REFIID riid,
464 VOID** ppvoid)
466 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
467 return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
470 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
472 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
473 return AutomationObject_AddRef((IDispatch *)This);
476 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
478 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
479 return AutomationObject_Release((IDispatch *)This);
482 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
484 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
485 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
486 return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
489 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
491 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
492 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
494 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
495 return E_INVALIDARG;
496 else {
497 *pGUID = *This->clsid;
498 return S_OK;
502 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
504 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
506 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
507 *pcti = 1;
508 return S_OK;
511 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
512 ULONG iti,
513 DWORD dwFlags,
514 ITypeInfo** pptiCoClass,
515 DWORD* pdwTIFlags,
516 ULONG* pcdispidReserved,
517 IID* piidPrimary,
518 IID* piidSource)
520 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
522 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
524 if (iti != 0)
525 return E_INVALIDARG;
527 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
528 load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
530 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
532 *pdwTIFlags = 0;
533 *pcdispidReserved = 0;
536 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
537 *piidPrimary = *This->clsid;
540 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
541 *piidSource = *This->clsid;
544 return S_OK;
547 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
549 AutomationObject_IProvideMultipleClassInfo_QueryInterface,
550 AutomationObject_IProvideMultipleClassInfo_AddRef,
551 AutomationObject_IProvideMultipleClassInfo_Release,
552 AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
553 AutomationObject_IProvideMultipleClassInfo_GetGUID,
554 AutomationObject_GetMultiTypeInfoCount,
555 AutomationObject_GetInfoOfIndex
559 * ListEnumerator methods
562 /*** IUnknown methods ***/
563 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, void** ppvObject)
565 ListEnumerator *This = (ListEnumerator *)iface;
567 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
569 if (ppvObject == NULL)
570 return E_INVALIDARG;
572 *ppvObject = 0;
574 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT))
575 *ppvObject = This;
576 else
578 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
579 return E_NOINTERFACE;
582 IClassFactory_AddRef(iface);
583 return S_OK;
586 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
588 ListEnumerator *This = (ListEnumerator *)iface;
590 TRACE("(%p/%p)\n", iface, This);
592 return InterlockedIncrement(&This->ref);
595 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
597 ListEnumerator *This = (ListEnumerator *)iface;
598 ULONG ref = InterlockedDecrement(&This->ref);
600 TRACE("(%p/%p)\n", iface, This);
602 if (!ref)
604 if (This->pObj) IDispatch_Release((IDispatch *)This->pObj);
605 HeapFree(GetProcessHeap(), 0, This);
608 return ref;
611 /* IEnumVARIANT methods */
613 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
615 ListEnumerator *This = (ListEnumerator *)iface;
616 ListData *data = (ListData *)private_data(This->pObj);
617 ULONG idx, local;
619 TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched);
621 if (pCeltFetched != NULL)
622 *pCeltFetched = 0;
624 if (rgVar == NULL)
625 return S_FALSE;
627 for (local = 0; local < celt; local++)
628 VariantInit(&rgVar[local]);
630 for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++)
631 VariantCopy(&rgVar[local], &data->pVars[idx]);
633 if (pCeltFetched != NULL)
634 *pCeltFetched = local;
635 This->ulPos = idx;
637 return (local < celt) ? S_FALSE : S_OK;
640 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
642 ListEnumerator *This = (ListEnumerator *)iface;
643 ListData *data = (ListData *)private_data(This->pObj);
645 TRACE("(%p,%uld)\n", iface, celt);
647 This->ulPos += celt;
648 if (This->ulPos >= data->ulCount)
650 This->ulPos = data->ulCount;
651 return S_FALSE;
653 return S_OK;
656 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
658 ListEnumerator *This = (ListEnumerator *)iface;
660 TRACE("(%p)\n", iface);
662 This->ulPos = 0;
663 return S_OK;
666 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
668 ListEnumerator *This = (ListEnumerator *)iface;
669 HRESULT hr;
671 TRACE("(%p,%p)\n", iface, ppEnum);
673 if (ppEnum == NULL)
674 return S_FALSE;
676 *ppEnum = NULL;
677 hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0);
678 if (FAILED(hr))
680 if (*ppEnum)
681 IUnknown_Release(*ppEnum);
682 return hr;
685 IUnknown_AddRef(*ppEnum);
686 return S_OK;
689 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
691 ListEnumerator_QueryInterface,
692 ListEnumerator_AddRef,
693 ListEnumerator_Release,
694 ListEnumerator_Next,
695 ListEnumerator_Skip,
696 ListEnumerator_Reset,
697 ListEnumerator_Clone
701 * Individual Object Invocation Functions
704 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
705 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
706 using DispGetParam/VariantChangeType. */
707 HRESULT WINAPI DispGetParam_CopyOnly(
708 DISPPARAMS *pdispparams, /* [in] Parameter list */
709 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
710 VARIANT *pvarResult) /* [out] Destination for resulting variant */
712 /* position is counted backwards */
713 UINT pos;
715 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
716 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
717 if (*position < pdispparams->cArgs) {
718 /* positional arg? */
719 pos = pdispparams->cArgs - *position - 1;
720 } else {
721 /* FIXME: is this how to handle named args? */
722 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
723 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
725 if (pos==pdispparams->cNamedArgs)
726 return DISP_E_PARAMNOTFOUND;
728 *position = pos;
729 return VariantCopyInd(pvarResult,
730 &pdispparams->rgvarg[pos]);
733 static HRESULT WINAPI SummaryInfoImpl_Invoke(
734 AutomationObject* This,
735 DISPID dispIdMember,
736 REFIID riid,
737 LCID lcid,
738 WORD wFlags,
739 DISPPARAMS* pDispParams,
740 VARIANT* pVarResult,
741 EXCEPINFO* pExcepInfo,
742 UINT* puArgErr)
744 UINT ret;
745 VARIANTARG varg0;
746 HRESULT hr;
748 VariantInit(&varg0);
750 switch (dispIdMember)
752 case DISPID_SUMMARYINFO_PROPERTY:
753 if (wFlags & DISPATCH_PROPERTYGET)
755 UINT type;
756 INT value;
757 INT pid;
759 static WCHAR szEmpty[] = {0};
761 VariantClear(pVarResult);
763 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
764 if (FAILED(hr)) return hr;
765 pid = V_I4(&varg0);
767 if (pid == PID_CODEPAGE || (pid >= PID_PAGECOUNT && pid <= PID_CHARCOUNT) || PID_SECURITY)
769 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, pid, &type, &value,
770 NULL, NULL, NULL);
771 if (ret != ERROR_SUCCESS)
772 return DISP_E_EXCEPTION;
774 if (pid == PID_CODEPAGE)
776 V_VT(pVarResult) = VT_I2;
777 V_I2(pVarResult) = value;
779 else
781 V_VT(pVarResult) = VT_I4;
782 V_I4(pVarResult) = value;
785 else if ((pid >= PID_TITLE && pid <= PID_REVNUMBER) || pid == PID_APPNAME)
787 LPWSTR str;
788 DWORD size = 0;
790 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, pid, &type, NULL,
791 NULL, szEmpty, &size);
792 if (ret != ERROR_MORE_DATA)
793 return DISP_E_EXCEPTION;
795 str = msi_alloc(++size * sizeof(WCHAR));
796 if (!str)
797 return DISP_E_EXCEPTION;
799 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, pid, &type, NULL,
800 NULL, str, &size);
801 if (ret != ERROR_SUCCESS)
803 msi_free(str);
804 return DISP_E_EXCEPTION;
807 V_VT(pVarResult) = VT_BSTR;
808 V_BSTR(pVarResult) = SysAllocString(str);
809 msi_free(str);
811 else if (pid >= PID_EDITTIME && pid <= PID_LASTSAVE_DTM)
813 FILETIME ft;
814 SYSTEMTIME st;
815 DATE date;
817 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, pid, &type, &value,
818 &ft, NULL, NULL);
819 if (ret != ERROR_SUCCESS)
820 return DISP_E_EXCEPTION;
822 FileTimeToSystemTime(&ft, &st);
823 SystemTimeToVariantTime(&st, &date);
825 V_VT(pVarResult) = VT_DATE;
826 V_DATE(pVarResult) = date;
829 else return DISP_E_MEMBERNOTFOUND;
830 break;
832 default:
833 ERR("Member not found: %d\n", dispIdMember);
834 return DISP_E_MEMBERNOTFOUND;
837 VariantClear(&varg0);
838 return S_OK;
841 static HRESULT WINAPI RecordImpl_Invoke(
842 AutomationObject* This,
843 DISPID dispIdMember,
844 REFIID riid,
845 LCID lcid,
846 WORD wFlags,
847 DISPPARAMS* pDispParams,
848 VARIANT* pVarResult,
849 EXCEPINFO* pExcepInfo,
850 UINT* puArgErr)
852 WCHAR *szString;
853 DWORD dwLen;
854 UINT ret;
855 VARIANTARG varg0, varg1;
856 HRESULT hr;
858 VariantInit(&varg0);
859 VariantInit(&varg1);
861 switch (dispIdMember)
863 case DISPID_RECORD_FIELDCOUNT:
864 if (wFlags & DISPATCH_PROPERTYGET) {
865 V_VT(pVarResult) = VT_I4;
866 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
868 else return DISP_E_MEMBERNOTFOUND;
869 break;
871 case DISPID_RECORD_STRINGDATA:
872 if (wFlags & DISPATCH_PROPERTYGET) {
873 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
874 if (FAILED(hr)) return hr;
875 V_VT(pVarResult) = VT_BSTR;
876 V_BSTR(pVarResult) = NULL;
877 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
879 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
880 ERR("Out of memory\n");
881 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
882 V_BSTR(pVarResult) = SysAllocString(szString);
883 msi_free(szString);
885 if (ret != ERROR_SUCCESS)
886 ERR("MsiRecordGetString returned %d\n", ret);
887 } else if (wFlags & DISPATCH_PROPERTYPUT) {
888 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
889 if (FAILED(hr)) return hr;
890 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
891 if (FAILED(hr)) return hr;
892 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
894 VariantClear(&varg1);
895 ERR("MsiRecordSetString returned %d\n", ret);
896 return DISP_E_EXCEPTION;
899 else return DISP_E_MEMBERNOTFOUND;
900 break;
902 case DISPID_RECORD_INTEGERDATA:
903 if (wFlags & DISPATCH_PROPERTYGET) {
904 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
905 if (FAILED(hr)) return hr;
906 V_VT(pVarResult) = VT_I4;
907 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
908 } else if (wFlags & DISPATCH_PROPERTYPUT) {
909 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
910 if (FAILED(hr)) return hr;
911 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
912 if (FAILED(hr)) return hr;
913 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
915 ERR("MsiRecordSetInteger returned %d\n", ret);
916 return DISP_E_EXCEPTION;
919 else return DISP_E_MEMBERNOTFOUND;
920 break;
922 default:
923 return DISP_E_MEMBERNOTFOUND;
926 VariantClear(&varg1);
927 VariantClear(&varg0);
929 return S_OK;
932 static HRESULT WINAPI ListImpl_Invoke(
933 AutomationObject* This,
934 DISPID dispIdMember,
935 REFIID riid,
936 LCID lcid,
937 WORD wFlags,
938 DISPPARAMS* pDispParams,
939 VARIANT* pVarResult,
940 EXCEPINFO* pExcepInfo,
941 UINT* puArgErr)
943 ListData *data = (ListData *)private_data(This);
944 HRESULT hr;
945 VARIANTARG varg0;
946 IUnknown *pUnk = NULL;
948 VariantInit(&varg0);
950 switch (dispIdMember)
952 case DISPID_LIST__NEWENUM:
953 if (wFlags & DISPATCH_METHOD) {
954 V_VT(pVarResult) = VT_UNKNOWN;
955 if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0)))
957 IUnknown_AddRef(pUnk);
958 V_UNKNOWN(pVarResult) = pUnk;
960 else
961 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
963 else return DISP_E_MEMBERNOTFOUND;
964 break;
966 case DISPID_LIST_ITEM:
967 if (wFlags & DISPATCH_PROPERTYGET) {
968 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
969 if (FAILED(hr)) return hr;
970 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount)
971 return DISP_E_BADINDEX;
972 VariantCopy(pVarResult, &data->pVars[V_I4(&varg0)]);
974 else return DISP_E_MEMBERNOTFOUND;
975 break;
977 case DISPID_LIST_COUNT:
978 if (wFlags & DISPATCH_PROPERTYGET) {
979 V_VT(pVarResult) = VT_I4;
980 V_I4(pVarResult) = data->ulCount;
982 else return DISP_E_MEMBERNOTFOUND;
983 break;
985 default:
986 return DISP_E_MEMBERNOTFOUND;
989 VariantClear(&varg0);
991 return S_OK;
994 static void WINAPI ListImpl_Free(AutomationObject *This)
996 ListData *data = private_data(This);
997 ULONG idx;
999 for (idx=0; idx<data->ulCount; idx++)
1000 VariantClear(&data->pVars[idx]);
1001 HeapFree(GetProcessHeap(), 0, data->pVars);
1004 static HRESULT WINAPI ViewImpl_Invoke(
1005 AutomationObject* This,
1006 DISPID dispIdMember,
1007 REFIID riid,
1008 LCID lcid,
1009 WORD wFlags,
1010 DISPPARAMS* pDispParams,
1011 VARIANT* pVarResult,
1012 EXCEPINFO* pExcepInfo,
1013 UINT* puArgErr)
1015 MSIHANDLE msiHandle;
1016 IDispatch *pDispatch = NULL;
1017 UINT ret;
1018 VARIANTARG varg0, varg1;
1019 HRESULT hr;
1021 VariantInit(&varg0);
1022 VariantInit(&varg1);
1024 switch (dispIdMember)
1026 case DISPID_VIEW_EXECUTE:
1027 if (wFlags & DISPATCH_METHOD)
1029 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1030 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1031 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1032 else
1033 MsiViewExecute(This->msiHandle, 0);
1035 else return DISP_E_MEMBERNOTFOUND;
1036 break;
1038 case DISPID_VIEW_FETCH:
1039 if (wFlags & DISPATCH_METHOD)
1041 V_VT(pVarResult) = VT_DISPATCH;
1042 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1044 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1046 IDispatch_AddRef(pDispatch);
1047 V_DISPATCH(pVarResult) = pDispatch;
1049 else
1050 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1052 else if (ret == ERROR_NO_MORE_ITEMS)
1053 V_DISPATCH(pVarResult) = NULL;
1054 else
1056 ERR("MsiViewFetch returned %d\n", ret);
1057 return DISP_E_EXCEPTION;
1060 else return DISP_E_MEMBERNOTFOUND;
1061 break;
1063 case DISPID_VIEW_MODIFY:
1064 if (wFlags & DISPATCH_METHOD)
1066 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1067 if (FAILED(hr)) return hr;
1068 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1069 if (FAILED(hr)) return hr;
1070 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1071 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1073 VariantClear(&varg1);
1074 ERR("MsiViewModify returned %d\n", ret);
1075 return DISP_E_EXCEPTION;
1078 else return DISP_E_MEMBERNOTFOUND;
1079 break;
1081 case DISPID_VIEW_CLOSE:
1082 if (wFlags & DISPATCH_METHOD)
1084 MsiViewClose(This->msiHandle);
1086 else return DISP_E_MEMBERNOTFOUND;
1087 break;
1089 default:
1090 return DISP_E_MEMBERNOTFOUND;
1093 VariantClear(&varg1);
1094 VariantClear(&varg0);
1096 return S_OK;
1099 static HRESULT WINAPI DatabaseImpl_Invoke(
1100 AutomationObject* This,
1101 DISPID dispIdMember,
1102 REFIID riid,
1103 LCID lcid,
1104 WORD wFlags,
1105 DISPPARAMS* pDispParams,
1106 VARIANT* pVarResult,
1107 EXCEPINFO* pExcepInfo,
1108 UINT* puArgErr)
1110 MSIHANDLE msiHandle;
1111 IDispatch *pDispatch = NULL;
1112 UINT ret;
1113 VARIANTARG varg0, varg1;
1114 HRESULT hr;
1116 VariantInit(&varg0);
1117 VariantInit(&varg1);
1119 switch (dispIdMember)
1121 case DISPID_DATABASE_SUMMARYINFORMATION:
1122 if (wFlags & DISPATCH_METHOD)
1124 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1125 if (FAILED(hr))
1126 V_I4(&varg0) = 0;
1128 V_VT(pVarResult) = VT_DISPATCH;
1129 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1131 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0);
1132 if (SUCCEEDED(hr))
1134 IDispatch_AddRef(pDispatch);
1135 V_DISPATCH(pVarResult) = pDispatch;
1137 else
1138 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1140 else
1142 ERR("MsiGetSummaryInformation returned %d\n", ret);
1143 return DISP_E_EXCEPTION;
1146 else return DISP_E_MEMBERNOTFOUND;
1147 break;
1149 case DISPID_DATABASE_OPENVIEW:
1150 if (wFlags & DISPATCH_METHOD)
1152 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1153 if (FAILED(hr)) return hr;
1154 V_VT(pVarResult) = VT_DISPATCH;
1155 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1157 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1159 IDispatch_AddRef(pDispatch);
1160 V_DISPATCH(pVarResult) = pDispatch;
1162 else
1163 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1165 else
1167 VariantClear(&varg0);
1168 ERR("MsiDatabaseOpenView returned %d\n", ret);
1169 return DISP_E_EXCEPTION;
1172 else return DISP_E_MEMBERNOTFOUND;
1173 break;
1175 default:
1176 return DISP_E_MEMBERNOTFOUND;
1179 VariantClear(&varg1);
1180 VariantClear(&varg0);
1182 return S_OK;
1185 static HRESULT WINAPI SessionImpl_Invoke(
1186 AutomationObject* This,
1187 DISPID dispIdMember,
1188 REFIID riid,
1189 LCID lcid,
1190 WORD wFlags,
1191 DISPPARAMS* pDispParams,
1192 VARIANT* pVarResult,
1193 EXCEPINFO* pExcepInfo,
1194 UINT* puArgErr)
1196 SessionData *data = private_data(This);
1197 WCHAR *szString;
1198 DWORD dwLen;
1199 IDispatch *pDispatch = NULL;
1200 MSIHANDLE msiHandle;
1201 LANGID langId;
1202 UINT ret;
1203 INSTALLSTATE iInstalled, iAction;
1204 VARIANTARG varg0, varg1;
1205 HRESULT hr;
1207 VariantInit(&varg0);
1208 VariantInit(&varg1);
1210 switch (dispIdMember)
1212 case DISPID_SESSION_INSTALLER:
1213 if (wFlags & DISPATCH_PROPERTYGET) {
1214 V_VT(pVarResult) = VT_DISPATCH;
1215 IDispatch_AddRef(data->pInstaller);
1216 V_DISPATCH(pVarResult) = data->pInstaller;
1218 else return DISP_E_MEMBERNOTFOUND;
1219 break;
1221 case DISPID_SESSION_PROPERTY:
1222 if (wFlags & DISPATCH_PROPERTYGET) {
1223 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1224 if (FAILED(hr)) return hr;
1225 V_VT(pVarResult) = VT_BSTR;
1226 V_BSTR(pVarResult) = NULL;
1227 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1229 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1230 ERR("Out of memory\n");
1231 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1232 V_BSTR(pVarResult) = SysAllocString(szString);
1233 msi_free(szString);
1235 if (ret != ERROR_SUCCESS)
1236 ERR("MsiGetProperty returned %d\n", ret);
1237 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1238 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1239 if (FAILED(hr)) return hr;
1240 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1241 if (FAILED(hr)) {
1242 VariantClear(&varg0);
1243 return hr;
1245 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1247 VariantClear(&varg0);
1248 VariantClear(&varg1);
1249 ERR("MsiSetProperty returned %d\n", ret);
1250 return DISP_E_EXCEPTION;
1253 else return DISP_E_MEMBERNOTFOUND;
1254 break;
1256 case DISPID_SESSION_LANGUAGE:
1257 if (wFlags & DISPATCH_PROPERTYGET) {
1258 langId = MsiGetLanguage(This->msiHandle);
1259 V_VT(pVarResult) = VT_I4;
1260 V_I4(pVarResult) = langId;
1262 else return DISP_E_MEMBERNOTFOUND;
1263 break;
1265 case DISPID_SESSION_MODE:
1266 if (wFlags & DISPATCH_PROPERTYGET) {
1267 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1268 if (FAILED(hr)) return hr;
1269 V_VT(pVarResult) = VT_BOOL;
1270 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1271 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1272 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1273 if (FAILED(hr)) return hr;
1274 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1275 if (FAILED(hr)) return hr;
1276 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1278 ERR("MsiSetMode returned %d\n", ret);
1279 return DISP_E_EXCEPTION;
1282 else return DISP_E_MEMBERNOTFOUND;
1283 break;
1285 case DISPID_SESSION_DATABASE:
1286 if (wFlags & DISPATCH_PROPERTYGET) {
1287 V_VT(pVarResult) = VT_DISPATCH;
1288 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1290 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1292 IDispatch_AddRef(pDispatch);
1293 V_DISPATCH(pVarResult) = pDispatch;
1295 else
1296 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1298 else
1300 ERR("MsiGetActiveDatabase failed\n");
1301 return DISP_E_EXCEPTION;
1304 else return DISP_E_MEMBERNOTFOUND;
1305 break;
1307 case DISPID_SESSION_DOACTION:
1308 if (wFlags & DISPATCH_METHOD) {
1309 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1310 if (FAILED(hr)) return hr;
1311 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1312 V_VT(pVarResult) = VT_I4;
1313 switch (ret)
1315 case ERROR_FUNCTION_NOT_CALLED:
1316 V_I4(pVarResult) = msiDoActionStatusNoAction;
1317 break;
1318 case ERROR_SUCCESS:
1319 V_I4(pVarResult) = msiDoActionStatusSuccess;
1320 break;
1321 case ERROR_INSTALL_USEREXIT:
1322 V_I4(pVarResult) = msiDoActionStatusUserExit;
1323 break;
1324 case ERROR_INSTALL_FAILURE:
1325 V_I4(pVarResult) = msiDoActionStatusFailure;
1326 break;
1327 case ERROR_INSTALL_SUSPEND:
1328 V_I4(pVarResult) = msiDoActionStatusSuspend;
1329 break;
1330 case ERROR_MORE_DATA:
1331 V_I4(pVarResult) = msiDoActionStatusFinished;
1332 break;
1333 case ERROR_INVALID_HANDLE_STATE:
1334 V_I4(pVarResult) = msiDoActionStatusWrongState;
1335 break;
1336 case ERROR_INVALID_DATA:
1337 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1338 break;
1339 default:
1340 VariantClear(&varg0);
1341 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1342 return DISP_E_EXCEPTION;
1345 else return DISP_E_MEMBERNOTFOUND;
1346 break;
1348 case DISPID_SESSION_EVALUATECONDITION:
1349 if (wFlags & DISPATCH_METHOD) {
1350 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1351 if (FAILED(hr)) return hr;
1352 V_VT(pVarResult) = VT_I4;
1353 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1355 else return DISP_E_MEMBERNOTFOUND;
1356 break;
1358 case DISPID_SESSION_SETINSTALLLEVEL:
1359 if (wFlags & DISPATCH_METHOD) {
1360 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1361 if (FAILED(hr)) return hr;
1362 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1364 ERR("MsiSetInstallLevel returned %d\n", ret);
1365 return DISP_E_EXCEPTION;
1368 else return DISP_E_MEMBERNOTFOUND;
1369 break;
1371 case DISPID_SESSION_FEATURECURRENTSTATE:
1372 if (wFlags & DISPATCH_PROPERTYGET) {
1373 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1374 if (FAILED(hr)) return hr;
1375 V_VT(pVarResult) = VT_I4;
1376 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1377 V_I4(pVarResult) = iInstalled;
1378 else
1380 ERR("MsiGetFeatureState returned %d\n", ret);
1381 V_I4(pVarResult) = msiInstallStateUnknown;
1384 else return DISP_E_MEMBERNOTFOUND;
1385 break;
1387 case DISPID_SESSION_FEATUREREQUESTSTATE:
1388 if (wFlags & DISPATCH_PROPERTYGET) {
1389 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1390 if (FAILED(hr)) return hr;
1391 V_VT(pVarResult) = VT_I4;
1392 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1393 V_I4(pVarResult) = iAction;
1394 else
1396 ERR("MsiGetFeatureState returned %d\n", ret);
1397 V_I4(pVarResult) = msiInstallStateUnknown;
1399 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1400 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1401 if (FAILED(hr)) return hr;
1402 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1403 if (FAILED(hr)) {
1404 VariantClear(&varg0);
1405 return hr;
1407 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1409 VariantClear(&varg0);
1410 ERR("MsiSetFeatureState returned %d\n", ret);
1411 return DISP_E_EXCEPTION;
1414 else return DISP_E_MEMBERNOTFOUND;
1415 break;
1417 default:
1418 return DISP_E_MEMBERNOTFOUND;
1421 VariantClear(&varg1);
1422 VariantClear(&varg0);
1424 return S_OK;
1427 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1428 * registry value type. Used by Installer::RegistryValue. */
1429 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1431 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1432 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1433 WCHAR *szString = (WCHAR *)lpData;
1434 LPWSTR szNewString = NULL;
1435 DWORD dwNewSize = 0;
1436 int idx;
1438 switch (dwType)
1440 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1441 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1442 idx = (dwSize/sizeof(WCHAR))-1;
1443 while (idx >= 0 && !szString[idx]) idx--;
1444 for (; idx >= 0; idx--)
1445 if (!szString[idx]) szString[idx] = '\n';
1446 case REG_SZ:
1447 V_VT(pVarResult) = VT_BSTR;
1448 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1449 break;
1451 case REG_EXPAND_SZ:
1452 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1453 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1454 else if (!(szNewString = msi_alloc(dwNewSize)))
1455 ERR("Out of memory\n");
1456 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1457 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1458 else
1460 V_VT(pVarResult) = VT_BSTR;
1461 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1463 msi_free(szNewString);
1464 break;
1466 case REG_DWORD:
1467 V_VT(pVarResult) = VT_I4;
1468 V_I4(pVarResult) = *((DWORD *)lpData);
1469 break;
1471 case REG_QWORD:
1472 V_VT(pVarResult) = VT_BSTR;
1473 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1474 break;
1476 case REG_BINARY:
1477 V_VT(pVarResult) = VT_BSTR;
1478 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1479 break;
1481 case REG_NONE:
1482 V_VT(pVarResult) = VT_EMPTY;
1483 break;
1485 default:
1486 FIXME("Unhandled registry value type %d\n", dwType);
1490 static HRESULT WINAPI InstallerImpl_Invoke(
1491 AutomationObject* This,
1492 DISPID dispIdMember,
1493 REFIID riid,
1494 LCID lcid,
1495 WORD wFlags,
1496 DISPPARAMS* pDispParams,
1497 VARIANT* pVarResult,
1498 EXCEPINFO* pExcepInfo,
1499 UINT* puArgErr)
1501 MSIHANDLE msiHandle;
1502 IDispatch *pDispatch = NULL;
1503 UINT ret;
1504 VARIANTARG varg0, varg1, varg2;
1505 HRESULT hr;
1506 LPWSTR szString = NULL;
1507 DWORD dwSize = 0;
1509 VariantInit(&varg0);
1510 VariantInit(&varg1);
1511 VariantInit(&varg2);
1513 switch (dispIdMember)
1515 case DISPID_INSTALLER_CREATERECORD:
1516 if (wFlags & DISPATCH_METHOD)
1518 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1519 if (FAILED(hr)) return hr;
1520 V_VT(pVarResult) = VT_DISPATCH;
1521 if ((msiHandle = MsiCreateRecord(V_I4(&varg0))))
1523 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1525 IDispatch_AddRef(pDispatch);
1526 V_DISPATCH(pVarResult) = pDispatch;
1528 else
1529 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1531 else
1533 ERR("MsiCreateRecord failed\n");
1534 return DISP_E_EXCEPTION;
1537 else return DISP_E_MEMBERNOTFOUND;
1538 break;
1540 case DISPID_INSTALLER_OPENPACKAGE:
1541 if (wFlags & DISPATCH_METHOD)
1543 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1544 if (FAILED(hr)) return hr;
1545 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1546 if (FAILED(hr))
1548 VariantClear(&varg0);
1549 return hr;
1551 V_VT(pVarResult) = VT_DISPATCH;
1552 if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
1554 if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
1556 IDispatch_AddRef(pDispatch);
1557 V_DISPATCH(pVarResult) = pDispatch;
1559 else
1560 ERR("Failed to create Session object, hresult 0x%08x\n", hr);
1562 else
1564 VariantClear(&varg0);
1565 ERR("MsiOpenPackageEx returned %d\n", ret);
1566 return DISP_E_EXCEPTION;
1569 else return DISP_E_MEMBERNOTFOUND;
1570 break;
1572 case DISPID_INSTALLER_OPENDATABASE:
1573 if (wFlags & DISPATCH_METHOD)
1575 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1576 if (FAILED(hr)) return hr;
1578 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1579 if (FAILED(hr))
1581 VariantClear(&varg0);
1582 return hr;
1585 V_VT(pVarResult) = VT_DISPATCH;
1586 if ((ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &msiHandle)) == ERROR_SUCCESS)
1588 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch,
1589 &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1590 if (SUCCEEDED(hr))
1592 IDispatch_AddRef(pDispatch);
1593 V_DISPATCH(pVarResult) = pDispatch;
1595 else
1596 ERR("Failed to create Database object: 0x%08x\n", hr);
1598 else
1600 VariantClear(&varg0);
1601 VariantClear(&varg1);
1602 ERR("MsiOpenDatabase returned %d\n", ret);
1603 return DISP_E_EXCEPTION;
1606 else return DISP_E_MEMBERNOTFOUND;
1607 break;
1609 case DISPID_INSTALLER_INSTALLPRODUCT:
1610 if (wFlags & DISPATCH_METHOD)
1612 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1613 if (FAILED(hr)) return hr;
1614 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1615 if (FAILED(hr))
1617 VariantClear(&varg0);
1618 return hr;
1620 if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1622 VariantClear(&varg1);
1623 VariantClear(&varg0);
1624 ERR("MsiInstallProduct returned %d\n", ret);
1625 return DISP_E_EXCEPTION;
1628 else return DISP_E_MEMBERNOTFOUND;
1629 break;
1631 case DISPID_INSTALLER_REGISTRYVALUE:
1632 if (wFlags & DISPATCH_METHOD) {
1633 HKEY hkey;
1634 DWORD dwType;
1635 UINT posValue = 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1637 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1638 if (FAILED(hr)) return hr;
1639 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1640 if (FAILED(hr)) return hr;
1641 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1642 if (FAILED(hr))
1644 VariantClear(&varg1);
1645 return hr;
1647 ret = RegOpenKeyW((HKEY)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1649 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1650 switch (V_VT(&varg2))
1652 case VT_EMPTY: /* Return VT_BOOL as to whether or not registry key exists */
1653 V_VT(pVarResult) = VT_BOOL;
1654 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1655 break;
1657 case VT_BSTR: /* Return value of specified key if it exists */
1658 if (ret == ERROR_SUCCESS &&
1659 (ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, NULL, NULL, &dwSize)) == ERROR_SUCCESS)
1661 if (!(szString = msi_alloc(dwSize)))
1662 ERR("Out of memory\n");
1663 else if ((ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, &dwType, (LPBYTE)szString, &dwSize)) == ERROR_SUCCESS)
1664 variant_from_registry_value(pVarResult, dwType, (LPBYTE)szString, dwSize);
1667 if (ret != ERROR_SUCCESS)
1669 msi_free(szString);
1670 VariantClear(&varg2);
1671 VariantClear(&varg1);
1672 return DISP_E_BADINDEX;
1674 break;
1676 default: /* Try to make it into VT_I4, can use VariantChangeType for this */
1677 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1678 if (SUCCEEDED(hr) && ret != ERROR_SUCCESS) hr = DISP_E_BADINDEX; /* Conversion fine, but couldn't find key */
1679 if (FAILED(hr))
1681 if (hr == DISP_E_TYPEMISMATCH) *puArgErr = posValue;
1682 VariantClear(&varg2); /* Unknown type, so let's clear it */
1683 VariantClear(&varg1);
1684 return hr;
1687 /* Retrieve class name or maximum value name or subkey name size */
1688 if (!V_I4(&varg2))
1689 ret = RegQueryInfoKeyW(hkey, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1690 else if (V_I4(&varg2) > 0)
1691 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL);
1692 else /* V_I4(&varg2) < 0 */
1693 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
1695 if (ret == ERROR_SUCCESS)
1697 if (!(szString = msi_alloc(++dwSize * sizeof(WCHAR))))
1698 ERR("Out of memory\n");
1699 else if (!V_I4(&varg2))
1700 ret = RegQueryInfoKeyW(hkey, szString, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1701 else if (V_I4(&varg2) > 0)
1702 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString, &dwSize, 0, 0, NULL, NULL);
1703 else /* V_I4(&varg2) < 0 */
1704 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, dwSize);
1706 if (szString && ret == ERROR_SUCCESS)
1708 V_VT(pVarResult) = VT_BSTR;
1709 V_BSTR(pVarResult) = SysAllocString(szString);
1714 msi_free(szString);
1715 RegCloseKey(hkey);
1717 else return DISP_E_MEMBERNOTFOUND;
1718 break;
1720 case DISPID_INSTALLER_PRODUCTSTATE:
1721 if (wFlags & DISPATCH_PROPERTYGET) {
1722 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1723 if (FAILED(hr)) return hr;
1724 V_VT(pVarResult) = VT_I4;
1725 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
1727 else return DISP_E_MEMBERNOTFOUND;
1728 break;
1730 case DISPID_INSTALLER_PRODUCTINFO:
1731 if (wFlags & DISPATCH_PROPERTYGET) {
1732 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1733 if (FAILED(hr)) return hr;
1734 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1735 if (FAILED(hr))
1737 VariantClear(&varg0);
1738 return hr;
1740 V_VT(pVarResult) = VT_BSTR;
1741 V_BSTR(pVarResult) = NULL;
1742 if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &dwSize)) == ERROR_SUCCESS)
1744 if (!(szString = msi_alloc((++dwSize)*sizeof(WCHAR))))
1745 ERR("Out of memory\n");
1746 else if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), szString, &dwSize)) == ERROR_SUCCESS)
1747 V_BSTR(pVarResult) = SysAllocString(szString);
1748 msi_free(szString);
1750 if (ret != ERROR_SUCCESS)
1752 ERR("MsiGetProductInfo returned %d\n", ret);
1753 VariantClear(&varg1);
1754 VariantClear(&varg0);
1755 return DISP_E_EXCEPTION;
1758 else return DISP_E_MEMBERNOTFOUND;
1759 break;
1761 case DISPID_INSTALLER_PRODUCTS:
1762 if (wFlags & DISPATCH_PROPERTYGET)
1764 ListData *ldata = NULL;
1765 ULONG idx = 0;
1766 WCHAR szProductBuf[GUID_SIZE];
1768 /* Find number of products */
1769 while ((ret = MsiEnumProductsW(idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1770 if (ret != ERROR_NO_MORE_ITEMS)
1772 ERR("MsiEnumProducts returned %d\n", ret);
1773 return DISP_E_EXCEPTION;
1776 V_VT(pVarResult) = VT_DISPATCH;
1777 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1779 IDispatch_AddRef(pDispatch);
1780 V_DISPATCH(pVarResult) = pDispatch;
1782 /* Save product strings */
1783 ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1784 if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1785 ERR("Out of memory\n");
1786 else
1788 ldata->ulCount = idx;
1789 for (idx = 0; idx < ldata->ulCount; idx++)
1791 ret = MsiEnumProductsW(idx, szProductBuf);
1792 VariantInit(&ldata->pVars[idx]);
1793 V_VT(&ldata->pVars[idx]) = VT_BSTR;
1794 V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1798 else
1799 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1801 else return DISP_E_MEMBERNOTFOUND;
1802 break;
1804 case DISPID_INSTALLER_RELATEDPRODUCTS:
1805 if (wFlags & DISPATCH_PROPERTYGET)
1807 ListData *ldata = NULL;
1808 ULONG idx = 0;
1809 WCHAR szProductBuf[GUID_SIZE];
1811 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1812 if (FAILED(hr)) return hr;
1814 /* Find number of related products */
1815 while ((ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1816 if (ret != ERROR_NO_MORE_ITEMS)
1818 VariantClear(&varg0);
1819 ERR("MsiEnumRelatedProducts returned %d\n", ret);
1820 return DISP_E_EXCEPTION;
1823 V_VT(pVarResult) = VT_DISPATCH;
1824 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1826 IDispatch_AddRef(pDispatch);
1827 V_DISPATCH(pVarResult) = pDispatch;
1829 /* Save product strings */
1830 ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1831 if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1832 ERR("Out of memory\n");
1833 else
1835 ldata->ulCount = idx;
1836 for (idx = 0; idx < ldata->ulCount; idx++)
1838 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf);
1839 VariantInit(&ldata->pVars[idx]);
1840 V_VT(&ldata->pVars[idx]) = VT_BSTR;
1841 V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1845 else
1846 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1848 else return DISP_E_MEMBERNOTFOUND;
1849 break;
1851 default:
1852 ERR("Member not found: %d\n", dispIdMember);
1853 return DISP_E_MEMBERNOTFOUND;
1856 VariantClear(&varg2);
1857 VariantClear(&varg1);
1858 VariantClear(&varg0);
1860 return S_OK;
1863 /* Wrapper around create_automation_object to create an installer object. */
1864 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
1866 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
1869 /* Wrapper around create_automation_object to create a session object. */
1870 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
1872 HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
1873 if (SUCCEEDED(hr) && pDispatch && *pDispatch)
1874 ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
1875 return hr;