mf/session: Forward more events to the application.
[wine/zf.git] / dlls / msi / automation.c
blob80d6b8a66ba9d3ff392cd328612f6e2886dba2db
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"
36 #include "msiserver.h"
37 #include "msiserver_dispids.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41 #define REG_INDEX_CLASSES_ROOT 0
42 #define REG_INDEX_DYN_DATA 6
44 typedef struct AutomationObject AutomationObject;
46 /* function that is called from AutomationObject::Invoke, specific to this type of object */
47 typedef HRESULT (*auto_invoke_func)(AutomationObject* This,
48 DISPID dispIdMember, REFIID riid, LCID lcid, WORD flags, DISPPARAMS* pDispParams,
49 VARIANT* result, EXCEPINFO* ei, UINT* arg_err);
50 /* function that is called from AutomationObject::Release when the object is being freed
51 to free any private data structures (or NULL) */
52 typedef void (*auto_free_func)(AutomationObject* This);
54 typedef struct {
55 REFIID riid;
56 auto_invoke_func fn_invoke;
57 auto_free_func fn_free;
58 } tid_id_t;
61 static HRESULT database_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
62 static HRESULT installer_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
63 static HRESULT record_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
64 static HRESULT session_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
65 static HRESULT list_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
66 static void list_free(AutomationObject*);
67 static HRESULT summaryinfo_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
68 static HRESULT view_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
70 static tid_id_t tid_ids[] = {
71 { &DIID_Database, database_invoke },
72 { &DIID_Installer, installer_invoke },
73 { &DIID_Record, record_invoke },
74 { &DIID_Session, session_invoke },
75 { &DIID_StringList, list_invoke, list_free },
76 { &DIID_SummaryInfo, summaryinfo_invoke },
77 { &DIID_View, view_invoke }
80 static ITypeLib *typelib;
81 static ITypeInfo *typeinfos[LAST_tid];
83 static const IID *get_riid_from_tid(tid_t tid)
85 return tid_ids[tid].riid;
88 HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo)
90 HRESULT hr;
92 if (!typelib)
94 ITypeLib *lib;
96 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, LOCALE_NEUTRAL, &lib);
97 if (FAILED(hr)) {
98 hr = LoadTypeLib(L"msiserver.tlb", &lib);
99 if (FAILED(hr)) {
100 ERR("Could not load msiserver.tlb\n");
101 return hr;
105 if (InterlockedCompareExchangePointer((void**)&typelib, lib, NULL))
106 ITypeLib_Release(lib);
109 if (!typeinfos[tid])
111 ITypeInfo *ti;
113 hr = ITypeLib_GetTypeInfoOfGuid(typelib, get_riid_from_tid(tid), &ti);
114 if (FAILED(hr)) {
115 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(get_riid_from_tid(tid)));
116 return hr;
119 if(InterlockedCompareExchangePointer((void**)(typeinfos+tid), ti, NULL))
120 ITypeInfo_Release(ti);
123 *typeinfo = typeinfos[tid];
124 return S_OK;
127 void release_typelib(void)
129 unsigned i;
131 for (i = 0; i < ARRAY_SIZE(typeinfos); i++)
132 if (typeinfos[i])
133 ITypeInfo_Release(typeinfos[i]);
135 if (typelib)
136 ITypeLib_Release(typelib);
140 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
141 * called from AutomationObject::Invoke.
143 struct AutomationObject {
144 IDispatch IDispatch_iface;
145 IProvideMultipleClassInfo IProvideMultipleClassInfo_iface;
146 LONG ref;
148 /* type id for this class */
149 tid_t tid;
151 /* The MSI handle of the current object */
152 MSIHANDLE msiHandle;
155 typedef struct {
156 AutomationObject autoobj;
157 int count;
158 VARIANT *data;
159 } ListObject;
161 static HRESULT create_database(MSIHANDLE, IDispatch**);
162 static HRESULT create_list_enumerator(ListObject*, void**);
163 static HRESULT create_summaryinfo(MSIHANDLE, IDispatch**);
164 static HRESULT create_view(MSIHANDLE, IDispatch**);
166 /* ListEnumerator - IEnumVARIANT implementation for MSI automation lists */
167 typedef struct {
168 IEnumVARIANT IEnumVARIANT_iface;
169 LONG ref;
171 /* Current position and pointer to AutomationObject that stores actual data */
172 ULONG pos;
173 ListObject *list;
174 } ListEnumerator;
176 typedef struct {
177 AutomationObject autoobj;
178 IDispatch *installer;
179 } SessionObject;
181 static inline AutomationObject *impl_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
183 return CONTAINING_RECORD(iface, AutomationObject, IProvideMultipleClassInfo_iface);
186 static inline AutomationObject *impl_from_IDispatch( IDispatch *iface )
188 return CONTAINING_RECORD(iface, AutomationObject, IDispatch_iface);
191 /* AutomationObject methods */
192 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
194 AutomationObject *This = impl_from_IDispatch(iface);
196 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
198 if (ppvObject == NULL)
199 return E_INVALIDARG;
201 *ppvObject = 0;
203 if (IsEqualGUID(riid, &IID_IUnknown) ||
204 IsEqualGUID(riid, &IID_IDispatch) ||
205 IsEqualGUID(riid, get_riid_from_tid(This->tid)))
206 *ppvObject = &This->IDispatch_iface;
207 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
208 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
209 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
210 *ppvObject = &This->IProvideMultipleClassInfo_iface;
211 else
213 TRACE("() : asking for unsupported interface %s\n", debugstr_guid(riid));
214 return E_NOINTERFACE;
217 IDispatch_AddRef(iface);
219 return S_OK;
222 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
224 AutomationObject *This = impl_from_IDispatch(iface);
226 TRACE("(%p/%p)\n", iface, This);
228 return InterlockedIncrement(&This->ref);
231 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
233 AutomationObject *This = impl_from_IDispatch(iface);
234 ULONG ref = InterlockedDecrement(&This->ref);
236 TRACE("(%p/%p)\n", iface, This);
238 if (!ref)
240 if (tid_ids[This->tid].fn_free) tid_ids[This->tid].fn_free(This);
241 MsiCloseHandle(This->msiHandle);
242 msi_free(This);
245 return ref;
248 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
249 IDispatch* iface,
250 UINT* pctinfo)
252 AutomationObject *This = impl_from_IDispatch(iface);
254 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
255 *pctinfo = 1;
256 return S_OK;
259 static HRESULT WINAPI AutomationObject_GetTypeInfo(
260 IDispatch* iface,
261 UINT iTInfo,
262 LCID lcid,
263 ITypeInfo** ppTInfo)
265 AutomationObject *This = impl_from_IDispatch(iface);
266 HRESULT hr;
268 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
270 hr = get_typeinfo(This->tid, ppTInfo);
271 if (FAILED(hr))
272 return hr;
274 ITypeInfo_AddRef(*ppTInfo);
275 return hr;
278 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
279 IDispatch* iface,
280 REFIID riid,
281 LPOLESTR* rgszNames,
282 UINT cNames,
283 LCID lcid,
284 DISPID* rgDispId)
286 AutomationObject *This = impl_from_IDispatch(iface);
287 ITypeInfo *ti;
288 HRESULT hr;
290 TRACE("(%p/%p)->(%s, %p, %d, %d, %p)\n", iface, This,
291 debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
293 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
295 hr = get_typeinfo(This->tid, &ti);
296 if (FAILED(hr))
297 return hr;
299 hr = ITypeInfo_GetIDsOfNames(ti, rgszNames, cNames, rgDispId);
300 if (hr == DISP_E_UNKNOWNNAME)
302 UINT idx;
303 for (idx=0; idx<cNames; idx++)
305 if (rgDispId[idx] == DISPID_UNKNOWN)
306 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(get_riid_from_tid(This->tid)));
309 return hr;
312 /* Maximum number of allowed function parameters+1 */
313 #define MAX_FUNC_PARAMS 20
315 /* Some error checking is done here to simplify individual object function invocation */
316 static HRESULT WINAPI AutomationObject_Invoke(
317 IDispatch* iface,
318 DISPID dispIdMember,
319 REFIID riid,
320 LCID lcid,
321 WORD wFlags,
322 DISPPARAMS* pDispParams,
323 VARIANT* pVarResult,
324 EXCEPINFO* pExcepInfo,
325 UINT* puArgErr)
327 AutomationObject *This = impl_from_IDispatch(iface);
328 HRESULT hr;
329 unsigned int uArgErr;
330 VARIANT varResultDummy;
331 BSTR bstrName = NULL;
332 ITypeInfo *ti;
334 TRACE("(%p/%p)->(%d, %s, %d, %d, %p, %p, %p, %p)\n", iface, This,
335 dispIdMember, debugstr_guid(riid), lcid, wFlags,
336 pDispParams, pVarResult, pExcepInfo, puArgErr);
338 if (!IsEqualIID(riid, &IID_NULL))
340 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
341 return DISP_E_UNKNOWNNAME;
344 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
346 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
347 return DISP_E_PARAMNOTOPTIONAL;
350 /* This simplifies our individual object invocation functions */
351 if (puArgErr == NULL) puArgErr = &uArgErr;
352 if (pVarResult == NULL) pVarResult = &varResultDummy;
354 hr = get_typeinfo(This->tid, &ti);
355 if (FAILED(hr))
356 return hr;
358 /* Assume return type is void unless determined otherwise */
359 VariantInit(pVarResult);
361 /* If we are tracing, we want to see the name of the member we are invoking */
362 if (TRACE_ON(msi))
364 ITypeInfo_GetDocumentation(ti, dispIdMember, &bstrName, NULL, NULL, NULL);
365 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
368 hr = tid_ids[This->tid].fn_invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
370 if (hr == DISP_E_MEMBERNOTFOUND) {
371 if (bstrName == NULL) ITypeInfo_GetDocumentation(ti, dispIdMember, &bstrName, NULL, NULL, NULL);
372 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags,
373 debugstr_guid(get_riid_from_tid(This->tid)));
375 else if (pExcepInfo &&
376 (hr == DISP_E_PARAMNOTFOUND ||
377 hr == DISP_E_EXCEPTION)) {
378 WCHAR szExceptionDescription[MAX_PATH];
379 BSTR bstrParamNames[MAX_FUNC_PARAMS];
380 unsigned namesNo, i;
381 BOOL bFirst = TRUE;
383 if (FAILED(ITypeInfo_GetNames(ti, dispIdMember, bstrParamNames,
384 MAX_FUNC_PARAMS, &namesNo)))
386 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
388 else
390 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
391 for (i=0; i<namesNo; i++)
393 if (bFirst) bFirst = FALSE;
394 else {
395 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], L",");
397 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
398 SysFreeString(bstrParamNames[i]);
401 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
402 pExcepInfo->wCode = 1000;
403 pExcepInfo->bstrSource = SysAllocString(L"Msi API Error");
404 pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
405 hr = DISP_E_EXCEPTION;
409 /* Make sure we free the return variant if it is our dummy variant */
410 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
412 /* Free function name if we retrieved it */
413 SysFreeString(bstrName);
415 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
417 return hr;
420 static const struct IDispatchVtbl AutomationObjectVtbl =
422 AutomationObject_QueryInterface,
423 AutomationObject_AddRef,
424 AutomationObject_Release,
425 AutomationObject_GetTypeInfoCount,
426 AutomationObject_GetTypeInfo,
427 AutomationObject_GetIDsOfNames,
428 AutomationObject_Invoke
432 * IProvideMultipleClassInfo methods
435 static HRESULT WINAPI ProvideMultipleClassInfo_QueryInterface(
436 IProvideMultipleClassInfo* iface,
437 REFIID riid,
438 VOID** ppvoid)
440 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
441 return IDispatch_QueryInterface(&This->IDispatch_iface, riid, ppvoid);
444 static ULONG WINAPI ProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
446 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
447 return IDispatch_AddRef(&This->IDispatch_iface);
450 static ULONG WINAPI ProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
452 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
453 return IDispatch_Release(&This->IDispatch_iface);
456 static HRESULT WINAPI ProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
458 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
459 HRESULT hr;
461 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
463 hr = get_typeinfo(This->tid, ppTI);
464 if (SUCCEEDED(hr))
465 ITypeInfo_AddRef(*ppTI);
467 return hr;
470 static HRESULT WINAPI ProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
472 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
473 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
475 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
476 return E_INVALIDARG;
477 else {
478 *pGUID = *get_riid_from_tid(This->tid);
479 return S_OK;
483 static HRESULT WINAPI ProvideMultipleClassInfo_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
485 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
487 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
488 *pcti = 1;
489 return S_OK;
492 static HRESULT WINAPI ProvideMultipleClassInfo_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
493 ULONG iti,
494 DWORD dwFlags,
495 ITypeInfo** ti,
496 DWORD* pdwTIFlags,
497 ULONG* pcdispidReserved,
498 IID* piidPrimary,
499 IID* piidSource)
501 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
503 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, ti, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
505 if (iti != 0)
506 return E_INVALIDARG;
508 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
510 HRESULT hr = get_typeinfo(This->tid, ti);
511 if (FAILED(hr))
512 return hr;
514 ITypeInfo_AddRef(*ti);
517 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
519 *pdwTIFlags = 0;
520 *pcdispidReserved = 0;
523 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY)
524 *piidPrimary = *get_riid_from_tid(This->tid);
526 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE)
527 *piidSource = *get_riid_from_tid(This->tid);
529 return S_OK;
532 static const IProvideMultipleClassInfoVtbl ProvideMultipleClassInfoVtbl =
534 ProvideMultipleClassInfo_QueryInterface,
535 ProvideMultipleClassInfo_AddRef,
536 ProvideMultipleClassInfo_Release,
537 ProvideMultipleClassInfo_GetClassInfo,
538 ProvideMultipleClassInfo_GetGUID,
539 ProvideMultipleClassInfo_GetMultiTypeInfoCount,
540 ProvideMultipleClassInfo_GetInfoOfIndex
543 static void init_automation_object(AutomationObject *This, MSIHANDLE msiHandle, tid_t tid)
545 TRACE("(%p, %d, %s)\n", This, msiHandle, debugstr_guid(get_riid_from_tid(tid)));
547 This->IDispatch_iface.lpVtbl = &AutomationObjectVtbl;
548 This->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl;
549 This->ref = 1;
550 This->msiHandle = msiHandle;
551 This->tid = tid;
555 * ListEnumerator methods
558 static inline ListEnumerator *impl_from_IEnumVARIANT(IEnumVARIANT* iface)
560 return CONTAINING_RECORD(iface, ListEnumerator, IEnumVARIANT_iface);
563 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid,
564 void** ppvObject)
566 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
568 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
570 if (ppvObject == NULL)
571 return E_INVALIDARG;
573 *ppvObject = 0;
575 if (IsEqualGUID(riid, &IID_IUnknown) ||
576 IsEqualGUID(riid, &IID_IEnumVARIANT))
578 *ppvObject = &This->IEnumVARIANT_iface;
580 else
582 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
583 return E_NOINTERFACE;
586 IEnumVARIANT_AddRef(iface);
587 return S_OK;
590 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
592 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
594 TRACE("(%p/%p)\n", iface, This);
596 return InterlockedIncrement(&This->ref);
599 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
601 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
602 ULONG ref = InterlockedDecrement(&This->ref);
604 TRACE("(%p/%p)\n", iface, This);
606 if (!ref)
608 if (This->list) IDispatch_Release(&This->list->autoobj.IDispatch_iface);
609 msi_free(This);
612 return ref;
615 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar,
616 ULONG* fetched)
618 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
619 ULONG i, local;
621 TRACE("(%p, %uld, %p, %p)\n", iface, celt, rgVar, fetched);
623 if (fetched) *fetched = 0;
625 if (!rgVar)
626 return S_FALSE;
628 for (local = 0; local < celt; local++)
629 VariantInit(&rgVar[local]);
631 for (i = This->pos, local = 0; i < This->list->count && local < celt; i++, local++)
632 VariantCopy(&rgVar[local], &This->list->data[i]);
634 if (fetched) *fetched = local;
635 This->pos = i;
637 return (local < celt) ? S_FALSE : S_OK;
640 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
642 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
644 TRACE("(%p,%uld)\n", iface, celt);
646 This->pos += celt;
647 if (This->pos >= This->list->count)
649 This->pos = This->list->count;
650 return S_FALSE;
653 return S_OK;
656 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
658 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
660 TRACE("(%p)\n", iface);
662 This->pos = 0;
663 return S_OK;
666 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
668 ListEnumerator *This = impl_from_IEnumVARIANT(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(This->list, (LPVOID *)ppEnum);
678 if (FAILED(hr))
680 if (*ppEnum) IEnumVARIANT_Release(*ppEnum);
681 return hr;
684 return S_OK;
687 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
689 ListEnumerator_QueryInterface,
690 ListEnumerator_AddRef,
691 ListEnumerator_Release,
692 ListEnumerator_Next,
693 ListEnumerator_Skip,
694 ListEnumerator_Reset,
695 ListEnumerator_Clone
698 /* Create a list enumerator, placing the result in the pointer ppObj. */
699 static HRESULT create_list_enumerator(ListObject *list, void **ppObj)
701 ListEnumerator *object;
703 TRACE("(%p, %p)\n", list, ppObj);
705 object = msi_alloc(sizeof(ListEnumerator));
707 /* Set all the VTable references */
708 object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
709 object->ref = 1;
711 /* Store data that was passed */
712 object->pos = 0;
713 object->list = list;
714 if (list) IDispatch_AddRef(&list->autoobj.IDispatch_iface);
716 *ppObj = object;
717 return S_OK;
721 * Individual Object Invocation Functions
724 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
725 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
726 using DispGetParam/VariantChangeType. */
727 static HRESULT DispGetParam_CopyOnly(
728 DISPPARAMS *pdispparams, /* [in] Parameter list */
729 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
730 VARIANT *pvarResult) /* [out] Destination for resulting variant */
732 /* position is counted backwards */
733 UINT pos;
735 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
736 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
737 if (*position < pdispparams->cArgs) {
738 /* positional arg? */
739 pos = pdispparams->cArgs - *position - 1;
740 } else {
741 /* FIXME: is this how to handle named args? */
742 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
743 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
745 if (pos==pdispparams->cNamedArgs)
746 return DISP_E_PARAMNOTFOUND;
748 *position = pos;
749 return VariantCopyInd(pvarResult,
750 &pdispparams->rgvarg[pos]);
753 static HRESULT summaryinfo_invoke(
754 AutomationObject* This,
755 DISPID dispIdMember,
756 REFIID riid,
757 LCID lcid,
758 WORD wFlags,
759 DISPPARAMS* pDispParams,
760 VARIANT* pVarResult,
761 EXCEPINFO* pExcepInfo,
762 UINT* puArgErr)
764 UINT ret;
765 VARIANTARG varg0, varg1;
766 FILETIME ft, ftlocal;
767 SYSTEMTIME st;
768 HRESULT hr;
770 VariantInit(&varg0);
771 VariantInit(&varg1);
773 switch (dispIdMember)
775 case DISPID_SUMMARYINFO_PROPERTY:
776 if (wFlags & DISPATCH_PROPERTYGET)
778 UINT type;
779 INT value;
780 DWORD size = 0;
781 DATE date;
782 LPWSTR str;
784 static WCHAR szEmpty[] = L"";
786 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
787 if (FAILED(hr)) return hr;
788 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
789 &ft, szEmpty, &size);
790 if (ret != ERROR_SUCCESS &&
791 ret != ERROR_MORE_DATA)
793 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
794 return DISP_E_EXCEPTION;
797 switch (type)
799 case VT_EMPTY:
800 break;
802 case VT_I2:
803 case VT_I4:
804 V_VT(pVarResult) = VT_I4;
805 V_I4(pVarResult) = value;
806 break;
808 case VT_LPSTR:
809 if (!(str = msi_alloc(++size * sizeof(WCHAR))))
810 ERR("Out of memory\n");
811 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
812 NULL, str, &size)) != ERROR_SUCCESS)
813 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
814 else
816 V_VT(pVarResult) = VT_BSTR;
817 V_BSTR(pVarResult) = SysAllocString(str);
819 msi_free(str);
820 break;
822 case VT_FILETIME:
823 FileTimeToLocalFileTime(&ft, &ftlocal);
824 FileTimeToSystemTime(&ftlocal, &st);
825 SystemTimeToVariantTime(&st, &date);
827 V_VT(pVarResult) = VT_DATE;
828 V_DATE(pVarResult) = date;
829 break;
831 default:
832 ERR("Unhandled variant type %d\n", type);
835 else if (wFlags & DISPATCH_PROPERTYPUT)
837 UINT posValue = DISPID_PROPERTYPUT;
839 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
840 if (FAILED(hr)) return hr;
841 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
842 if (FAILED(hr))
844 *puArgErr = posValue;
845 return hr;
848 switch (V_VT(&varg1))
850 case VT_I2:
851 case VT_I4:
852 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
853 break;
855 case VT_DATE:
856 VariantTimeToSystemTime(V_DATE(&varg1), &st);
857 SystemTimeToFileTime(&st, &ftlocal);
858 LocalFileTimeToFileTime(&ftlocal, &ft);
859 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
860 break;
862 case VT_BSTR:
863 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
864 break;
866 default:
867 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
868 VariantClear(&varg1);
869 return DISP_E_EXCEPTION;
872 if (ret != ERROR_SUCCESS)
874 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
875 return DISP_E_EXCEPTION;
878 else return DISP_E_MEMBERNOTFOUND;
879 break;
881 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
882 if (wFlags & DISPATCH_PROPERTYGET) {
883 UINT count;
884 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
885 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
886 else
888 V_VT(pVarResult) = VT_I4;
889 V_I4(pVarResult) = count;
892 else return DISP_E_MEMBERNOTFOUND;
893 break;
895 default:
896 return DISP_E_MEMBERNOTFOUND;
899 VariantClear(&varg1);
900 VariantClear(&varg0);
902 return S_OK;
905 static HRESULT record_invoke(
906 AutomationObject* This,
907 DISPID dispIdMember,
908 REFIID riid,
909 LCID lcid,
910 WORD wFlags,
911 DISPPARAMS* pDispParams,
912 VARIANT* pVarResult,
913 EXCEPINFO* pExcepInfo,
914 UINT* puArgErr)
916 WCHAR *szString;
917 DWORD dwLen = 0;
918 UINT ret;
919 VARIANTARG varg0, varg1;
920 HRESULT hr;
922 VariantInit(&varg0);
923 VariantInit(&varg1);
925 switch (dispIdMember)
927 case DISPID_RECORD_FIELDCOUNT:
928 if (wFlags & DISPATCH_PROPERTYGET) {
929 V_VT(pVarResult) = VT_I4;
930 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
932 else return DISP_E_MEMBERNOTFOUND;
933 break;
935 case DISPID_RECORD_STRINGDATA:
936 if (wFlags & DISPATCH_PROPERTYGET) {
937 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
938 if (FAILED(hr)) return hr;
939 V_VT(pVarResult) = VT_BSTR;
940 V_BSTR(pVarResult) = NULL;
941 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
943 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
944 ERR("Out of memory\n");
945 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
946 V_BSTR(pVarResult) = SysAllocString(szString);
947 msi_free(szString);
949 if (ret != ERROR_SUCCESS)
950 ERR("MsiRecordGetString returned %d\n", ret);
951 } else if (wFlags & DISPATCH_PROPERTYPUT) {
952 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
953 if (FAILED(hr)) return hr;
954 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
955 if (FAILED(hr)) return hr;
956 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
958 VariantClear(&varg1);
959 ERR("MsiRecordSetString returned %d\n", ret);
960 return DISP_E_EXCEPTION;
963 else return DISP_E_MEMBERNOTFOUND;
964 break;
966 case DISPID_RECORD_INTEGERDATA:
967 if (wFlags & DISPATCH_PROPERTYGET) {
968 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
969 if (FAILED(hr)) return hr;
970 V_VT(pVarResult) = VT_I4;
971 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
972 } else if (wFlags & DISPATCH_PROPERTYPUT) {
973 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
974 if (FAILED(hr)) return hr;
975 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
976 if (FAILED(hr)) return hr;
977 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
979 ERR("MsiRecordSetInteger returned %d\n", ret);
980 return DISP_E_EXCEPTION;
983 else return DISP_E_MEMBERNOTFOUND;
984 break;
986 default:
987 return DISP_E_MEMBERNOTFOUND;
990 VariantClear(&varg1);
991 VariantClear(&varg0);
993 return S_OK;
996 static HRESULT create_record(MSIHANDLE msiHandle, IDispatch **disp)
998 AutomationObject *record;
1000 record = msi_alloc(sizeof(*record));
1001 if (!record) return E_OUTOFMEMORY;
1003 init_automation_object(record, msiHandle, Record_tid);
1005 *disp = &record->IDispatch_iface;
1007 return S_OK;
1010 static HRESULT list_invoke(
1011 AutomationObject* This,
1012 DISPID dispIdMember,
1013 REFIID riid,
1014 LCID lcid,
1015 WORD wFlags,
1016 DISPPARAMS* pDispParams,
1017 VARIANT* pVarResult,
1018 EXCEPINFO* pExcepInfo,
1019 UINT* puArgErr)
1021 ListObject *list = CONTAINING_RECORD(This, ListObject, autoobj);
1022 IUnknown *pUnk = NULL;
1023 HRESULT hr;
1025 switch (dispIdMember)
1027 case DISPID_LIST__NEWENUM:
1028 if (wFlags & DISPATCH_METHOD) {
1029 V_VT(pVarResult) = VT_UNKNOWN;
1030 if (SUCCEEDED(hr = create_list_enumerator(list, (LPVOID *)&pUnk)))
1031 V_UNKNOWN(pVarResult) = pUnk;
1032 else
1033 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
1035 else return DISP_E_MEMBERNOTFOUND;
1036 break;
1038 case DISPID_LIST_ITEM:
1039 if (wFlags & DISPATCH_PROPERTYGET) {
1040 VARIANTARG index;
1042 VariantInit(&index);
1043 hr = DispGetParam(pDispParams, 0, VT_I4, &index, puArgErr);
1044 if (FAILED(hr)) return hr;
1045 if (V_I4(&index) < 0 || V_I4(&index) >= list->count)
1046 return DISP_E_BADINDEX;
1047 VariantCopy(pVarResult, &list->data[V_I4(&index)]);
1049 else return DISP_E_MEMBERNOTFOUND;
1050 break;
1052 case DISPID_LIST_COUNT:
1053 if (wFlags & DISPATCH_PROPERTYGET) {
1054 V_VT(pVarResult) = VT_I4;
1055 V_I4(pVarResult) = list->count;
1057 else return DISP_E_MEMBERNOTFOUND;
1058 break;
1060 default:
1061 return DISP_E_MEMBERNOTFOUND;
1064 return S_OK;
1067 static void list_free(AutomationObject *This)
1069 ListObject *list = CONTAINING_RECORD(This, ListObject, autoobj);
1070 int i;
1072 for (i = 0; i < list->count; i++)
1073 VariantClear(&list->data[i]);
1074 msi_free(list->data);
1077 static HRESULT get_products_count(const WCHAR *product, int *len)
1079 int i = 0;
1081 while (1)
1083 WCHAR dataW[GUID_SIZE];
1084 UINT ret;
1086 /* all or related only */
1087 if (product)
1088 ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1089 else
1090 ret = MsiEnumProductsW(i, dataW);
1092 if (ret == ERROR_NO_MORE_ITEMS) break;
1094 if (ret != ERROR_SUCCESS)
1095 return DISP_E_EXCEPTION;
1097 i++;
1100 *len = i;
1102 return S_OK;
1105 static HRESULT create_list(const WCHAR *product, IDispatch **dispatch)
1107 ListObject *list;
1108 HRESULT hr;
1109 int i;
1111 list = msi_alloc_zero(sizeof(ListObject));
1112 if (!list) return E_OUTOFMEMORY;
1114 init_automation_object(&list->autoobj, 0, StringList_tid);
1116 *dispatch = &list->autoobj.IDispatch_iface;
1118 hr = get_products_count(product, &list->count);
1119 if (hr != S_OK)
1121 IDispatch_Release(*dispatch);
1122 return hr;
1125 list->data = msi_alloc(list->count*sizeof(VARIANT));
1126 if (!list->data)
1128 IDispatch_Release(*dispatch);
1129 return E_OUTOFMEMORY;
1132 for (i = 0; i < list->count; i++)
1134 WCHAR dataW[GUID_SIZE];
1135 UINT ret;
1137 /* all or related only */
1138 if (product)
1139 ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1140 else
1141 ret = MsiEnumProductsW(i, dataW);
1143 if (ret == ERROR_NO_MORE_ITEMS) break;
1145 V_VT(&list->data[i]) = VT_BSTR;
1146 V_BSTR(&list->data[i]) = SysAllocString(dataW);
1149 return S_OK;
1152 static HRESULT view_invoke(
1153 AutomationObject* This,
1154 DISPID dispIdMember,
1155 REFIID riid,
1156 LCID lcid,
1157 WORD wFlags,
1158 DISPPARAMS* pDispParams,
1159 VARIANT* pVarResult,
1160 EXCEPINFO* pExcepInfo,
1161 UINT* puArgErr)
1163 MSIHANDLE msiHandle;
1164 UINT ret;
1165 VARIANTARG varg0, varg1;
1166 HRESULT hr;
1168 VariantInit(&varg0);
1169 VariantInit(&varg1);
1171 switch (dispIdMember)
1173 case DISPID_VIEW_EXECUTE:
1174 if (wFlags & DISPATCH_METHOD)
1176 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1177 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1178 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1179 else
1180 MsiViewExecute(This->msiHandle, 0);
1182 else return DISP_E_MEMBERNOTFOUND;
1183 break;
1185 case DISPID_VIEW_FETCH:
1186 if (wFlags & DISPATCH_METHOD)
1188 V_VT(pVarResult) = VT_DISPATCH;
1189 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1191 if (FAILED(hr = create_record(msiHandle, &V_DISPATCH(pVarResult))))
1192 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1194 else if (ret == ERROR_NO_MORE_ITEMS)
1195 V_DISPATCH(pVarResult) = NULL;
1196 else
1198 ERR("MsiViewFetch returned %d\n", ret);
1199 return DISP_E_EXCEPTION;
1202 else return DISP_E_MEMBERNOTFOUND;
1203 break;
1205 case DISPID_VIEW_MODIFY:
1206 if (wFlags & DISPATCH_METHOD)
1208 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1209 if (FAILED(hr)) return hr;
1210 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1211 if (FAILED(hr)) return hr;
1212 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1213 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1215 VariantClear(&varg1);
1216 ERR("MsiViewModify returned %d\n", ret);
1217 return DISP_E_EXCEPTION;
1220 else return DISP_E_MEMBERNOTFOUND;
1221 break;
1223 case DISPID_VIEW_CLOSE:
1224 if (wFlags & DISPATCH_METHOD)
1226 MsiViewClose(This->msiHandle);
1228 else return DISP_E_MEMBERNOTFOUND;
1229 break;
1231 default:
1232 return DISP_E_MEMBERNOTFOUND;
1235 VariantClear(&varg1);
1236 VariantClear(&varg0);
1238 return S_OK;
1241 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
1242 DISPPARAMS* pDispParams,
1243 VARIANT* pVarResult,
1244 EXCEPINFO* pExcepInfo,
1245 UINT* puArgErr)
1247 if (!(wFlags & DISPATCH_METHOD))
1248 return DISP_E_MEMBERNOTFOUND;
1250 FIXME("\n");
1252 VariantInit(pVarResult);
1253 return S_OK;
1256 HRESULT database_invoke(
1257 AutomationObject* This,
1258 DISPID dispIdMember,
1259 REFIID riid,
1260 LCID lcid,
1261 WORD wFlags,
1262 DISPPARAMS* pDispParams,
1263 VARIANT* pVarResult,
1264 EXCEPINFO* pExcepInfo,
1265 UINT* puArgErr)
1267 IDispatch *dispatch = NULL;
1268 MSIHANDLE msiHandle;
1269 UINT ret;
1270 VARIANTARG varg0, varg1;
1271 HRESULT hr;
1273 VariantInit(&varg0);
1274 VariantInit(&varg1);
1276 switch (dispIdMember)
1278 case DISPID_DATABASE_SUMMARYINFORMATION:
1279 if (wFlags & DISPATCH_PROPERTYGET)
1281 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1282 if (FAILED(hr))
1283 V_I4(&varg0) = 0;
1285 V_VT(pVarResult) = VT_DISPATCH;
1286 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1288 hr = create_summaryinfo(msiHandle, &dispatch);
1289 if (SUCCEEDED(hr))
1290 V_DISPATCH(pVarResult) = dispatch;
1291 else
1292 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1294 else
1296 ERR("MsiGetSummaryInformation returned %d\n", ret);
1297 return DISP_E_EXCEPTION;
1300 else return DISP_E_MEMBERNOTFOUND;
1301 break;
1303 case DISPID_DATABASE_OPENVIEW:
1304 if (wFlags & DISPATCH_METHOD)
1306 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1307 if (FAILED(hr)) return hr;
1308 V_VT(pVarResult) = VT_DISPATCH;
1309 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1311 if (SUCCEEDED(hr = create_view(msiHandle, &dispatch)))
1312 V_DISPATCH(pVarResult) = dispatch;
1313 else
1314 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1316 else
1318 VariantClear(&varg0);
1319 ERR("MsiDatabaseOpenView returned %d\n", ret);
1320 return DISP_E_EXCEPTION;
1323 else return DISP_E_MEMBERNOTFOUND;
1324 break;
1326 case DISPID_INSTALLER_LASTERRORRECORD:
1327 return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
1328 pVarResult, pExcepInfo,
1329 puArgErr);
1331 default:
1332 return DISP_E_MEMBERNOTFOUND;
1335 VariantClear(&varg1);
1336 VariantClear(&varg0);
1338 return S_OK;
1341 static HRESULT session_invoke(
1342 AutomationObject* This,
1343 DISPID dispIdMember,
1344 REFIID riid,
1345 LCID lcid,
1346 WORD wFlags,
1347 DISPPARAMS* pDispParams,
1348 VARIANT* pVarResult,
1349 EXCEPINFO* pExcepInfo,
1350 UINT* puArgErr)
1352 SessionObject *session = CONTAINING_RECORD(This, SessionObject, autoobj);
1353 WCHAR *szString;
1354 DWORD dwLen = 0;
1355 MSIHANDLE msiHandle;
1356 LANGID langId;
1357 UINT ret;
1358 INSTALLSTATE iInstalled, iAction;
1359 VARIANTARG varg0, varg1;
1360 HRESULT hr;
1362 VariantInit(&varg0);
1363 VariantInit(&varg1);
1365 switch (dispIdMember)
1367 case DISPID_SESSION_INSTALLER:
1368 if (wFlags & DISPATCH_PROPERTYGET) {
1369 V_VT(pVarResult) = VT_DISPATCH;
1370 IDispatch_AddRef(session->installer);
1371 V_DISPATCH(pVarResult) = session->installer;
1373 else return DISP_E_MEMBERNOTFOUND;
1374 break;
1376 case DISPID_SESSION_PROPERTY:
1377 if (wFlags & DISPATCH_PROPERTYGET) {
1378 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1379 if (FAILED(hr)) return hr;
1380 V_VT(pVarResult) = VT_BSTR;
1381 V_BSTR(pVarResult) = NULL;
1382 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1384 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1385 ERR("Out of memory\n");
1386 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1387 V_BSTR(pVarResult) = SysAllocString(szString);
1388 msi_free(szString);
1390 if (ret != ERROR_SUCCESS)
1391 ERR("MsiGetProperty returned %d\n", ret);
1392 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1393 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1394 if (FAILED(hr)) return hr;
1395 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1396 if (FAILED(hr)) {
1397 VariantClear(&varg0);
1398 return hr;
1400 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1402 VariantClear(&varg0);
1403 VariantClear(&varg1);
1404 ERR("MsiSetProperty returned %d\n", ret);
1405 return DISP_E_EXCEPTION;
1408 else return DISP_E_MEMBERNOTFOUND;
1409 break;
1411 case DISPID_SESSION_LANGUAGE:
1412 if (wFlags & DISPATCH_PROPERTYGET) {
1413 langId = MsiGetLanguage(This->msiHandle);
1414 V_VT(pVarResult) = VT_I4;
1415 V_I4(pVarResult) = langId;
1417 else return DISP_E_MEMBERNOTFOUND;
1418 break;
1420 case DISPID_SESSION_MODE:
1421 if (wFlags & DISPATCH_PROPERTYGET) {
1422 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1423 if (FAILED(hr)) return hr;
1424 V_VT(pVarResult) = VT_BOOL;
1425 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0)) ? VARIANT_TRUE : VARIANT_FALSE;
1426 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1427 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1428 if (FAILED(hr)) return hr;
1429 hr = DispGetParam(pDispParams, 1, VT_BOOL, &varg1, puArgErr);
1430 if (FAILED(hr)) return hr;
1431 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1433 ERR("MsiSetMode returned %d\n", ret);
1434 return DISP_E_EXCEPTION;
1437 else return DISP_E_MEMBERNOTFOUND;
1438 break;
1440 case DISPID_SESSION_DATABASE:
1441 if (wFlags & DISPATCH_PROPERTYGET) {
1442 V_VT(pVarResult) = VT_DISPATCH;
1443 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1445 IDispatch *dispatch;
1447 if (SUCCEEDED(hr = create_database(msiHandle, &dispatch)))
1448 V_DISPATCH(pVarResult) = dispatch;
1449 else
1450 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1452 else
1454 ERR("MsiGetActiveDatabase failed\n");
1455 return DISP_E_EXCEPTION;
1458 else return DISP_E_MEMBERNOTFOUND;
1459 break;
1461 case DISPID_SESSION_DOACTION:
1462 if (wFlags & DISPATCH_METHOD) {
1463 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1464 if (FAILED(hr)) return hr;
1465 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1466 V_VT(pVarResult) = VT_I4;
1467 switch (ret)
1469 case ERROR_FUNCTION_NOT_CALLED:
1470 V_I4(pVarResult) = msiDoActionStatusNoAction;
1471 break;
1472 case ERROR_SUCCESS:
1473 V_I4(pVarResult) = msiDoActionStatusSuccess;
1474 break;
1475 case ERROR_INSTALL_USEREXIT:
1476 V_I4(pVarResult) = msiDoActionStatusUserExit;
1477 break;
1478 case ERROR_INSTALL_FAILURE:
1479 V_I4(pVarResult) = msiDoActionStatusFailure;
1480 break;
1481 case ERROR_INSTALL_SUSPEND:
1482 V_I4(pVarResult) = msiDoActionStatusSuspend;
1483 break;
1484 case ERROR_MORE_DATA:
1485 V_I4(pVarResult) = msiDoActionStatusFinished;
1486 break;
1487 case ERROR_INVALID_HANDLE_STATE:
1488 V_I4(pVarResult) = msiDoActionStatusWrongState;
1489 break;
1490 case ERROR_INVALID_DATA:
1491 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1492 break;
1493 default:
1494 VariantClear(&varg0);
1495 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1496 return DISP_E_EXCEPTION;
1499 else return DISP_E_MEMBERNOTFOUND;
1500 break;
1502 case DISPID_SESSION_EVALUATECONDITION:
1503 if (wFlags & DISPATCH_METHOD) {
1504 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1505 if (FAILED(hr)) return hr;
1506 V_VT(pVarResult) = VT_I4;
1507 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1509 else return DISP_E_MEMBERNOTFOUND;
1510 break;
1512 case DISPID_SESSION_MESSAGE:
1513 if(!(wFlags & DISPATCH_METHOD))
1514 return DISP_E_MEMBERNOTFOUND;
1516 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1517 if (FAILED(hr)) return hr;
1518 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1519 if (FAILED(hr)) return hr;
1521 V_VT(pVarResult) = VT_I4;
1522 V_I4(pVarResult) =
1523 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
1524 break;
1526 case DISPID_SESSION_SETINSTALLLEVEL:
1527 if (wFlags & DISPATCH_METHOD) {
1528 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1529 if (FAILED(hr)) return hr;
1530 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1532 ERR("MsiSetInstallLevel returned %d\n", ret);
1533 return DISP_E_EXCEPTION;
1536 else return DISP_E_MEMBERNOTFOUND;
1537 break;
1539 case DISPID_SESSION_FEATURECURRENTSTATE:
1540 if (wFlags & DISPATCH_PROPERTYGET) {
1541 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1542 if (FAILED(hr)) return hr;
1543 V_VT(pVarResult) = VT_I4;
1544 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1545 V_I4(pVarResult) = iInstalled;
1546 else
1548 ERR("MsiGetFeatureState returned %d\n", ret);
1549 V_I4(pVarResult) = msiInstallStateUnknown;
1552 else return DISP_E_MEMBERNOTFOUND;
1553 break;
1555 case DISPID_SESSION_FEATUREREQUESTSTATE:
1556 if (wFlags & DISPATCH_PROPERTYGET) {
1557 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1558 if (FAILED(hr)) return hr;
1559 V_VT(pVarResult) = VT_I4;
1560 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1561 V_I4(pVarResult) = iAction;
1562 else
1564 ERR("MsiGetFeatureState returned %d\n", ret);
1565 V_I4(pVarResult) = msiInstallStateUnknown;
1567 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1568 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1569 if (FAILED(hr)) return hr;
1570 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1571 if (FAILED(hr)) {
1572 VariantClear(&varg0);
1573 return hr;
1575 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1577 VariantClear(&varg0);
1578 ERR("MsiSetFeatureState returned %d\n", ret);
1579 return DISP_E_EXCEPTION;
1582 else return DISP_E_MEMBERNOTFOUND;
1583 break;
1585 default:
1586 return DISP_E_MEMBERNOTFOUND;
1589 VariantClear(&varg1);
1590 VariantClear(&varg0);
1592 return S_OK;
1595 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1596 * registry value type. Used by Installer::RegistryValue. */
1597 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1599 WCHAR *szString = (WCHAR *)lpData;
1600 LPWSTR szNewString = NULL;
1601 DWORD dwNewSize = 0;
1602 int idx;
1604 switch (dwType)
1606 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1607 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1608 idx = (dwSize/sizeof(WCHAR))-1;
1609 while (idx >= 0 && !szString[idx]) idx--;
1610 for (; idx >= 0; idx--)
1611 if (!szString[idx]) szString[idx] = '\n';
1612 /* fall through */
1613 case REG_SZ:
1614 V_VT(pVarResult) = VT_BSTR;
1615 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1616 break;
1618 case REG_EXPAND_SZ:
1619 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1620 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1621 else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1622 ERR("Out of memory\n");
1623 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1624 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1625 else
1627 V_VT(pVarResult) = VT_BSTR;
1628 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1630 msi_free(szNewString);
1631 break;
1633 case REG_DWORD:
1634 V_VT(pVarResult) = VT_I4;
1635 V_I4(pVarResult) = *((DWORD *)lpData);
1636 break;
1638 case REG_QWORD:
1639 V_VT(pVarResult) = VT_BSTR;
1640 V_BSTR(pVarResult) = SysAllocString(L"(REG_\?\?)"); /* Weird string, don't know why native returns it */
1641 break;
1643 case REG_BINARY:
1644 V_VT(pVarResult) = VT_BSTR;
1645 V_BSTR(pVarResult) = SysAllocString(L"(REG_BINARY)");
1646 break;
1648 case REG_NONE:
1649 V_VT(pVarResult) = VT_EMPTY;
1650 break;
1652 default:
1653 FIXME("Unhandled registry value type %d\n", dwType);
1657 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1658 DISPPARAMS* pDispParams,
1659 VARIANT* pVarResult,
1660 EXCEPINFO* pExcepInfo,
1661 UINT* puArgErr)
1663 HRESULT hr;
1664 VARIANTARG varg0;
1665 MSIHANDLE hrec;
1667 if (!(wFlags & DISPATCH_METHOD))
1668 return DISP_E_MEMBERNOTFOUND;
1670 VariantInit(&varg0);
1671 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1672 if (FAILED(hr))
1673 return hr;
1675 V_VT(pVarResult) = VT_DISPATCH;
1677 hrec = MsiCreateRecord(V_I4(&varg0));
1678 if (!hrec)
1679 return DISP_E_EXCEPTION;
1681 return create_record(hrec, &V_DISPATCH(pVarResult));
1684 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1685 WORD wFlags,
1686 DISPPARAMS* pDispParams,
1687 VARIANT* pVarResult,
1688 EXCEPINFO* pExcepInfo,
1689 UINT* puArgErr)
1691 UINT ret;
1692 HRESULT hr;
1693 MSIHANDLE hpkg;
1694 IDispatch* dispatch;
1695 VARIANTARG varg0, varg1;
1697 if (!(wFlags & DISPATCH_METHOD))
1698 return DISP_E_MEMBERNOTFOUND;
1700 if (pDispParams->cArgs == 0)
1701 return DISP_E_TYPEMISMATCH;
1703 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1704 return DISP_E_TYPEMISMATCH;
1706 VariantInit(&varg0);
1707 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1708 if (FAILED(hr))
1709 return hr;
1711 VariantInit(&varg1);
1712 if (pDispParams->cArgs == 2)
1714 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1715 if (FAILED(hr))
1716 goto done;
1718 else
1720 V_VT(&varg1) = VT_I4;
1721 V_I4(&varg1) = 0;
1724 V_VT(pVarResult) = VT_DISPATCH;
1726 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1727 if (ret != ERROR_SUCCESS)
1729 hr = DISP_E_EXCEPTION;
1730 goto done;
1733 hr = create_session(hpkg, &This->IDispatch_iface, &dispatch);
1734 if (SUCCEEDED(hr))
1735 V_DISPATCH(pVarResult) = dispatch;
1737 done:
1738 VariantClear(&varg0);
1739 VariantClear(&varg1);
1740 return hr;
1743 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1744 DISPPARAMS* pDispParams,
1745 VARIANT* pVarResult,
1746 EXCEPINFO* pExcepInfo,
1747 UINT* puArgErr)
1749 HRESULT hr;
1750 VARIANTARG varg0;
1752 if (!(wFlags & DISPATCH_METHOD))
1753 return DISP_E_MEMBERNOTFOUND;
1755 VariantInit(&varg0);
1756 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1757 if (FAILED(hr))
1758 return hr;
1760 FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1762 VariantInit(pVarResult);
1764 VariantClear(&varg0);
1765 return S_OK;
1768 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1769 DISPPARAMS* pDispParams,
1770 VARIANT* pVarResult,
1771 EXCEPINFO* pExcepInfo,
1772 UINT* puArgErr)
1774 UINT ret;
1775 HRESULT hr;
1776 MSIHANDLE hdb;
1777 IDispatch* dispatch;
1778 VARIANTARG varg0, varg1;
1780 if (!(wFlags & DISPATCH_METHOD))
1781 return DISP_E_MEMBERNOTFOUND;
1783 VariantInit(&varg0);
1784 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1785 if (FAILED(hr))
1786 return hr;
1788 VariantInit(&varg1);
1789 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1790 if (FAILED(hr))
1791 goto done;
1793 V_VT(pVarResult) = VT_DISPATCH;
1795 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1796 if (ret != ERROR_SUCCESS)
1798 hr = DISP_E_EXCEPTION;
1799 goto done;
1802 hr = create_database(hdb, &dispatch);
1803 if (SUCCEEDED(hr))
1804 V_DISPATCH(pVarResult) = dispatch;
1806 done:
1807 VariantClear(&varg0);
1808 VariantClear(&varg1);
1809 return hr;
1812 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1813 DISPPARAMS* pDispParams,
1814 VARIANT* pVarResult,
1815 EXCEPINFO* pExcepInfo,
1816 UINT* puArgErr)
1818 UINT ret;
1819 HRESULT hr;
1820 MSIHANDLE hsuminfo;
1821 IDispatch *dispatch;
1822 VARIANTARG varg0, varg1;
1824 if (!(wFlags & DISPATCH_PROPERTYGET))
1825 return DISP_E_MEMBERNOTFOUND;
1827 VariantInit(&varg1);
1828 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1829 if (FAILED(hr))
1830 return hr;
1832 VariantInit(&varg0);
1833 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1834 if (FAILED(hr))
1835 return hr;
1837 ret = MsiGetSummaryInformationW(0, V_BSTR(&varg0), V_I4(&varg1), &hsuminfo);
1838 VariantClear(&varg0);
1839 if (ret != ERROR_SUCCESS)
1840 return DISP_E_EXCEPTION;
1842 hr = create_summaryinfo(hsuminfo, &dispatch);
1843 if (FAILED(hr))
1844 return hr;
1846 V_VT(pVarResult) = VT_DISPATCH;
1847 V_DISPATCH(pVarResult) = dispatch;
1848 return S_OK;
1851 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1852 DISPPARAMS* pDispParams,
1853 VARIANT* pVarResult,
1854 EXCEPINFO* pExcepInfo,
1855 UINT* puArgErr)
1857 HRESULT hr;
1858 VARIANTARG varg0;
1859 INSTALLUILEVEL ui;
1861 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1862 return DISP_E_MEMBERNOTFOUND;
1864 if (wFlags & DISPATCH_PROPERTYPUT)
1866 VariantInit(&varg0);
1867 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1868 if (FAILED(hr))
1869 return hr;
1871 ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1872 if (ui == INSTALLUILEVEL_NOCHANGE)
1873 return DISP_E_EXCEPTION;
1875 else if (wFlags & DISPATCH_PROPERTYGET)
1877 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1878 if (ui == INSTALLUILEVEL_NOCHANGE)
1879 return DISP_E_EXCEPTION;
1881 V_VT(pVarResult) = VT_I4;
1882 V_I4(pVarResult) = ui;
1885 return S_OK;
1888 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1889 DISPPARAMS* pDispParams,
1890 VARIANT* pVarResult,
1891 EXCEPINFO* pExcepInfo,
1892 UINT* puArgErr)
1894 if (!(wFlags & DISPATCH_METHOD))
1895 return DISP_E_MEMBERNOTFOUND;
1897 FIXME("\n");
1899 VariantInit(pVarResult);
1900 return S_OK;
1903 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1904 DISPPARAMS* pDispParams,
1905 VARIANT* pVarResult,
1906 EXCEPINFO* pExcepInfo,
1907 UINT* puArgErr)
1909 UINT ret;
1910 HRESULT hr;
1911 VARIANTARG varg0, varg1;
1913 if (!(wFlags & DISPATCH_METHOD))
1914 return DISP_E_MEMBERNOTFOUND;
1916 VariantInit(&varg0);
1917 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1918 if (FAILED(hr))
1919 return hr;
1921 VariantInit(&varg1);
1922 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1923 if (FAILED(hr))
1924 goto done;
1926 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1927 if (ret != ERROR_SUCCESS)
1929 hr = DISP_E_EXCEPTION;
1930 goto done;
1933 done:
1934 VariantClear(&varg0);
1935 VariantClear(&varg1);
1936 return hr;
1939 static HRESULT InstallerImpl_Version(WORD wFlags,
1940 VARIANT* pVarResult,
1941 EXCEPINFO* pExcepInfo,
1942 UINT* puArgErr)
1944 HRESULT hr;
1945 DLLVERSIONINFO verinfo;
1946 WCHAR version[MAX_PATH];
1948 if (!(wFlags & DISPATCH_PROPERTYGET))
1949 return DISP_E_MEMBERNOTFOUND;
1951 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1952 hr = DllGetVersion(&verinfo);
1953 if (FAILED(hr))
1954 return hr;
1956 swprintf(version, ARRAY_SIZE(version), L"%d.%d.%d.%d", verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1957 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1959 V_VT(pVarResult) = VT_BSTR;
1960 V_BSTR(pVarResult) = SysAllocString(version);
1961 return S_OK;
1964 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1965 DISPPARAMS* pDispParams,
1966 VARIANT* pVarResult,
1967 EXCEPINFO* pExcepInfo,
1968 UINT* puArgErr)
1970 if (!(wFlags & DISPATCH_METHOD))
1971 return DISP_E_MEMBERNOTFOUND;
1973 FIXME("\n");
1975 VariantInit(pVarResult);
1976 return S_OK;
1979 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1980 DISPPARAMS* pDispParams,
1981 VARIANT* pVarResult,
1982 EXCEPINFO* pExcepInfo,
1983 UINT* puArgErr)
1985 UINT ret;
1986 HKEY hkey = NULL;
1987 HRESULT hr;
1988 UINT posValue;
1989 DWORD type, size;
1990 LPWSTR szString = NULL;
1991 VARIANTARG varg0, varg1, varg2;
1993 if (!(wFlags & DISPATCH_METHOD))
1994 return DISP_E_MEMBERNOTFOUND;
1996 VariantInit(&varg0);
1997 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1998 if (FAILED(hr))
1999 return hr;
2001 VariantInit(&varg1);
2002 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2003 if (FAILED(hr))
2004 goto done;
2006 /* Save valuePos so we can save puArgErr if we are unable to do our type
2007 * conversions.
2009 posValue = 2;
2010 VariantInit(&varg2);
2011 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
2012 if (FAILED(hr))
2013 goto done;
2015 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
2016 V_I4(&varg0) <= REG_INDEX_DYN_DATA)
2018 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
2021 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
2023 /* Only VT_EMPTY case can do anything if the key doesn't exist. */
2024 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
2026 hr = DISP_E_BADINDEX;
2027 goto done;
2030 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
2031 switch (V_VT(&varg2))
2033 /* Return VT_BOOL clarifying whether registry key exists or not. */
2034 case VT_EMPTY:
2035 V_VT(pVarResult) = VT_BOOL;
2036 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS) ? VARIANT_TRUE : VARIANT_FALSE;
2037 break;
2039 /* Return the value of specified key if it exists. */
2040 case VT_BSTR:
2041 ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
2042 NULL, NULL, NULL, &size);
2043 if (ret != ERROR_SUCCESS)
2045 hr = DISP_E_BADINDEX;
2046 goto done;
2049 szString = msi_alloc(size);
2050 if (!szString)
2052 hr = E_OUTOFMEMORY;
2053 goto done;
2056 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
2057 &type, (LPBYTE)szString, &size);
2058 if (ret != ERROR_SUCCESS)
2060 msi_free(szString);
2061 hr = DISP_E_BADINDEX;
2062 goto done;
2065 variant_from_registry_value(pVarResult, type,
2066 (LPBYTE)szString, size);
2067 msi_free(szString);
2068 break;
2070 /* Try to make it into VT_I4, can use VariantChangeType for this. */
2071 default:
2072 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
2073 if (FAILED(hr))
2075 if (hr == DISP_E_TYPEMISMATCH)
2076 *puArgErr = posValue;
2078 goto done;
2081 /* Retrieve class name or maximum value name or subkey name size. */
2082 if (!V_I4(&varg2))
2083 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
2084 NULL, NULL, NULL, NULL, NULL, NULL);
2085 else if (V_I4(&varg2) > 0)
2086 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
2087 NULL, NULL, &size, NULL, NULL, NULL);
2088 else /* V_I4(&varg2) < 0 */
2089 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
2090 NULL, NULL, NULL, NULL, NULL, NULL);
2092 if (ret != ERROR_SUCCESS)
2093 goto done;
2095 szString = msi_alloc(++size * sizeof(WCHAR));
2096 if (!szString)
2098 hr = E_OUTOFMEMORY;
2099 goto done;
2102 if (!V_I4(&varg2))
2103 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
2104 NULL, NULL, NULL, NULL, NULL, NULL);
2105 else if (V_I4(&varg2) > 0)
2106 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
2107 &size, 0, 0, NULL, NULL);
2108 else /* V_I4(&varg2) < 0 */
2109 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
2111 if (ret == ERROR_SUCCESS)
2113 V_VT(pVarResult) = VT_BSTR;
2114 V_BSTR(pVarResult) = SysAllocString(szString);
2117 msi_free(szString);
2120 done:
2121 VariantClear(&varg0);
2122 VariantClear(&varg1);
2123 VariantClear(&varg2);
2124 RegCloseKey(hkey);
2125 return hr;
2128 static HRESULT InstallerImpl_Environment(WORD wFlags,
2129 DISPPARAMS* pDispParams,
2130 VARIANT* pVarResult,
2131 EXCEPINFO* pExcepInfo,
2132 UINT* puArgErr)
2134 if (!(wFlags & DISPATCH_METHOD))
2135 return DISP_E_MEMBERNOTFOUND;
2137 FIXME("\n");
2139 VariantInit(pVarResult);
2140 return S_OK;
2143 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2144 DISPPARAMS* pDispParams,
2145 VARIANT* pVarResult,
2146 EXCEPINFO* pExcepInfo,
2147 UINT* puArgErr)
2149 if (!(wFlags & DISPATCH_METHOD))
2150 return DISP_E_MEMBERNOTFOUND;
2152 FIXME("\n");
2154 VariantInit(pVarResult);
2155 return S_OK;
2158 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2159 DISPPARAMS* pDispParams,
2160 VARIANT* pVarResult,
2161 EXCEPINFO* pExcepInfo,
2162 UINT* puArgErr)
2164 if (!(wFlags & DISPATCH_METHOD))
2165 return DISP_E_MEMBERNOTFOUND;
2167 FIXME("\n");
2169 VariantInit(pVarResult);
2170 return S_OK;
2173 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2174 DISPPARAMS* pDispParams,
2175 VARIANT* pVarResult,
2176 EXCEPINFO* pExcepInfo,
2177 UINT* puArgErr)
2179 if (!(wFlags & DISPATCH_METHOD))
2180 return DISP_E_MEMBERNOTFOUND;
2182 FIXME("\n");
2184 VariantInit(pVarResult);
2185 return S_OK;
2188 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2189 DISPPARAMS* pDispParams,
2190 VARIANT* pVarResult,
2191 EXCEPINFO* pExcepInfo,
2192 UINT* puArgErr)
2194 HRESULT hr;
2195 VARIANTARG varg0;
2197 if (!(wFlags & DISPATCH_PROPERTYGET))
2198 return DISP_E_MEMBERNOTFOUND;
2200 VariantInit(&varg0);
2201 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2202 if (FAILED(hr))
2203 return hr;
2205 V_VT(pVarResult) = VT_I4;
2206 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2208 VariantClear(&varg0);
2209 return S_OK;
2212 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2213 DISPPARAMS* pDispParams,
2214 VARIANT* pVarResult,
2215 EXCEPINFO* pExcepInfo,
2216 UINT* puArgErr)
2218 UINT ret;
2219 HRESULT hr;
2220 DWORD size;
2221 LPWSTR str = NULL;
2222 VARIANTARG varg0, varg1;
2224 if (!(wFlags & DISPATCH_PROPERTYGET))
2225 return DISP_E_MEMBERNOTFOUND;
2227 VariantInit(&varg0);
2228 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2229 if (FAILED(hr))
2230 return hr;
2232 VariantInit(&varg1);
2233 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2234 if (FAILED(hr))
2235 goto done;
2237 V_VT(pVarResult) = VT_BSTR;
2238 V_BSTR(pVarResult) = NULL;
2240 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2241 if (ret != ERROR_SUCCESS)
2243 hr = DISP_E_EXCEPTION;
2244 goto done;
2247 str = msi_alloc(++size * sizeof(WCHAR));
2248 if (!str)
2250 hr = E_OUTOFMEMORY;
2251 goto done;
2254 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2255 if (ret != ERROR_SUCCESS)
2257 hr = DISP_E_EXCEPTION;
2258 goto done;
2261 V_BSTR(pVarResult) = SysAllocString(str);
2262 hr = S_OK;
2264 done:
2265 msi_free(str);
2266 VariantClear(&varg0);
2267 VariantClear(&varg1);
2268 return hr;
2271 static HRESULT InstallerImpl_Products(WORD flags,
2272 DISPPARAMS* pDispParams,
2273 VARIANT* result,
2274 EXCEPINFO* pExcepInfo,
2275 UINT* puArgErr)
2277 IDispatch *dispatch;
2278 HRESULT hr;
2280 if (!(flags & DISPATCH_PROPERTYGET))
2281 return DISP_E_MEMBERNOTFOUND;
2283 hr = create_list(NULL, &dispatch);
2284 if (FAILED(hr))
2285 return hr;
2287 V_VT(result) = VT_DISPATCH;
2288 V_DISPATCH(result) = dispatch;
2290 return hr;
2293 static HRESULT InstallerImpl_RelatedProducts(WORD flags,
2294 DISPPARAMS* pDispParams,
2295 VARIANT* result,
2296 EXCEPINFO* pExcepInfo,
2297 UINT* puArgErr)
2299 IDispatch* dispatch;
2300 VARIANTARG related;
2301 HRESULT hr;
2303 if (!(flags & DISPATCH_PROPERTYGET))
2304 return DISP_E_MEMBERNOTFOUND;
2306 VariantInit(&related);
2307 hr = DispGetParam(pDispParams, 0, VT_BSTR, &related, puArgErr);
2308 if (FAILED(hr))
2309 return hr;
2311 hr = create_list(V_BSTR(&related), &dispatch);
2312 VariantClear(&related);
2314 V_VT(result) = VT_DISPATCH;
2315 V_DISPATCH(result) = dispatch;
2317 return hr;
2320 static HRESULT installer_invoke(
2321 AutomationObject* This,
2322 DISPID dispIdMember,
2323 REFIID riid,
2324 LCID lcid,
2325 WORD wFlags,
2326 DISPPARAMS* pDispParams,
2327 VARIANT* pVarResult,
2328 EXCEPINFO* pExcepInfo,
2329 UINT* puArgErr)
2331 switch (dispIdMember)
2333 case DISPID_INSTALLER_CREATERECORD:
2334 return InstallerImpl_CreateRecord(wFlags, pDispParams,
2335 pVarResult, pExcepInfo, puArgErr);
2337 case DISPID_INSTALLER_OPENPACKAGE:
2338 return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2339 pVarResult, pExcepInfo, puArgErr);
2341 case DISPID_INSTALLER_OPENPRODUCT:
2342 return InstallerImpl_OpenProduct(wFlags, pDispParams,
2343 pVarResult, pExcepInfo, puArgErr);
2345 case DISPID_INSTALLER_OPENDATABASE:
2346 return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2347 pVarResult, pExcepInfo, puArgErr);
2349 case DISPID_INSTALLER_SUMMARYINFORMATION:
2350 return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2351 pVarResult, pExcepInfo,
2352 puArgErr);
2354 case DISPID_INSTALLER_UILEVEL:
2355 return InstallerImpl_UILevel(wFlags, pDispParams,
2356 pVarResult, pExcepInfo, puArgErr);
2358 case DISPID_INSTALLER_ENABLELOG:
2359 return InstallerImpl_EnableLog(wFlags, pDispParams,
2360 pVarResult, pExcepInfo, puArgErr);
2362 case DISPID_INSTALLER_INSTALLPRODUCT:
2363 return InstallerImpl_InstallProduct(wFlags, pDispParams,
2364 pVarResult, pExcepInfo,
2365 puArgErr);
2367 case DISPID_INSTALLER_VERSION:
2368 return InstallerImpl_Version(wFlags, pVarResult,
2369 pExcepInfo, puArgErr);
2371 case DISPID_INSTALLER_LASTERRORRECORD:
2372 return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2373 pVarResult, pExcepInfo,
2374 puArgErr);
2376 case DISPID_INSTALLER_REGISTRYVALUE:
2377 return InstallerImpl_RegistryValue(wFlags, pDispParams,
2378 pVarResult, pExcepInfo,
2379 puArgErr);
2381 case DISPID_INSTALLER_ENVIRONMENT:
2382 return InstallerImpl_Environment(wFlags, pDispParams,
2383 pVarResult, pExcepInfo, puArgErr);
2385 case DISPID_INSTALLER_FILEATTRIBUTES:
2386 return InstallerImpl_FileAttributes(wFlags, pDispParams,
2387 pVarResult, pExcepInfo,
2388 puArgErr);
2390 case DISPID_INSTALLER_FILESIZE:
2391 return InstallerImpl_FileSize(wFlags, pDispParams,
2392 pVarResult, pExcepInfo, puArgErr);
2394 case DISPID_INSTALLER_FILEVERSION:
2395 return InstallerImpl_FileVersion(wFlags, pDispParams,
2396 pVarResult, pExcepInfo, puArgErr);
2398 case DISPID_INSTALLER_PRODUCTSTATE:
2399 return InstallerImpl_ProductState(wFlags, pDispParams,
2400 pVarResult, pExcepInfo, puArgErr);
2402 case DISPID_INSTALLER_PRODUCTINFO:
2403 return InstallerImpl_ProductInfo(wFlags, pDispParams,
2404 pVarResult, pExcepInfo, puArgErr);
2406 case DISPID_INSTALLER_PRODUCTS:
2407 return InstallerImpl_Products(wFlags, pDispParams,
2408 pVarResult, pExcepInfo, puArgErr);
2410 case DISPID_INSTALLER_RELATEDPRODUCTS:
2411 return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2412 pVarResult, pExcepInfo,
2413 puArgErr);
2415 default:
2416 return DISP_E_MEMBERNOTFOUND;
2420 HRESULT create_msiserver(IUnknown *outer, void **ppObj)
2422 AutomationObject *installer;
2424 TRACE("(%p %p)\n", outer, ppObj);
2426 if (outer)
2427 return CLASS_E_NOAGGREGATION;
2429 installer = msi_alloc(sizeof(AutomationObject));
2430 if (!installer) return E_OUTOFMEMORY;
2432 init_automation_object(installer, 0, Installer_tid);
2434 *ppObj = &installer->IDispatch_iface;
2436 return S_OK;
2439 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp)
2441 SessionObject *session;
2443 session = msi_alloc(sizeof(SessionObject));
2444 if (!session) return E_OUTOFMEMORY;
2446 init_automation_object(&session->autoobj, msiHandle, Session_tid);
2448 session->installer = installer;
2449 *disp = &session->autoobj.IDispatch_iface;
2451 return S_OK;
2454 static HRESULT create_database(MSIHANDLE msiHandle, IDispatch **dispatch)
2456 AutomationObject *database;
2458 TRACE("(%d %p)\n", msiHandle, dispatch);
2460 database = msi_alloc(sizeof(AutomationObject));
2461 if (!database) return E_OUTOFMEMORY;
2463 init_automation_object(database, msiHandle, Database_tid);
2465 *dispatch = &database->IDispatch_iface;
2467 return S_OK;
2470 static HRESULT create_view(MSIHANDLE msiHandle, IDispatch **dispatch)
2472 AutomationObject *view;
2474 TRACE("(%d %p)\n", msiHandle, dispatch);
2476 view = msi_alloc(sizeof(AutomationObject));
2477 if (!view) return E_OUTOFMEMORY;
2479 init_automation_object(view, msiHandle, View_tid);
2481 *dispatch = &view->IDispatch_iface;
2483 return S_OK;
2486 static HRESULT create_summaryinfo(MSIHANDLE msiHandle, IDispatch **disp)
2488 AutomationObject *info;
2490 info = msi_alloc(sizeof(*info));
2491 if (!info) return E_OUTOFMEMORY;
2493 init_automation_object(info, msiHandle, SummaryInfo_tid);
2495 *disp = &info->IDispatch_iface;
2497 return S_OK;