windows.media.speech: Add IIterable<IInspectable*> stubs.
[wine.git] / dlls / msi / automation.c
blobf8fd8cc14498b3915c01c21032d89fa06d5c7943
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)->(%u, %ld, %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, %u, %ld, %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)->(%ld, %s, %ld, %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 %ld, %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 %ld, %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 %ld\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 %#lx, %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)->(%lu, %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)->(%lu, %#lx, %p, %p, %p, %p, %p)\n", iface, This, iti, dwFlags, ti, pdwTIFlags, pcdispidReserved,
504 piidPrimary, piidSource);
506 if (iti != 0)
507 return E_INVALIDARG;
509 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
511 HRESULT hr = get_typeinfo(This->tid, ti);
512 if (FAILED(hr))
513 return hr;
515 ITypeInfo_AddRef(*ti);
518 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
520 *pdwTIFlags = 0;
521 *pcdispidReserved = 0;
524 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY)
525 *piidPrimary = *get_riid_from_tid(This->tid);
527 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE)
528 *piidSource = *get_riid_from_tid(This->tid);
530 return S_OK;
533 static const IProvideMultipleClassInfoVtbl ProvideMultipleClassInfoVtbl =
535 ProvideMultipleClassInfo_QueryInterface,
536 ProvideMultipleClassInfo_AddRef,
537 ProvideMultipleClassInfo_Release,
538 ProvideMultipleClassInfo_GetClassInfo,
539 ProvideMultipleClassInfo_GetGUID,
540 ProvideMultipleClassInfo_GetMultiTypeInfoCount,
541 ProvideMultipleClassInfo_GetInfoOfIndex
544 static void init_automation_object(AutomationObject *This, MSIHANDLE msiHandle, tid_t tid)
546 TRACE("%p, %lu, %s\n", This, msiHandle, debugstr_guid(get_riid_from_tid(tid)));
548 This->IDispatch_iface.lpVtbl = &AutomationObjectVtbl;
549 This->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl;
550 This->ref = 1;
551 This->msiHandle = msiHandle;
552 This->tid = tid;
556 * ListEnumerator methods
559 static inline ListEnumerator *impl_from_IEnumVARIANT(IEnumVARIANT* iface)
561 return CONTAINING_RECORD(iface, ListEnumerator, IEnumVARIANT_iface);
564 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid,
565 void** ppvObject)
567 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
569 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
571 if (ppvObject == NULL)
572 return E_INVALIDARG;
574 *ppvObject = 0;
576 if (IsEqualGUID(riid, &IID_IUnknown) ||
577 IsEqualGUID(riid, &IID_IEnumVARIANT))
579 *ppvObject = &This->IEnumVARIANT_iface;
581 else
583 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
584 return E_NOINTERFACE;
587 IEnumVARIANT_AddRef(iface);
588 return S_OK;
591 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
593 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
595 TRACE("(%p/%p)\n", iface, This);
597 return InterlockedIncrement(&This->ref);
600 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
602 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
603 ULONG ref = InterlockedDecrement(&This->ref);
605 TRACE("(%p/%p)\n", iface, This);
607 if (!ref)
609 if (This->list) IDispatch_Release(&This->list->autoobj.IDispatch_iface);
610 msi_free(This);
613 return ref;
616 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar,
617 ULONG* fetched)
619 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
620 ULONG i, local;
622 TRACE("%p, %lu, %p, %p\n", iface, celt, rgVar, fetched);
624 if (fetched) *fetched = 0;
626 if (!rgVar)
627 return S_FALSE;
629 for (local = 0; local < celt; local++)
630 VariantInit(&rgVar[local]);
632 for (i = This->pos, local = 0; i < This->list->count && local < celt; i++, local++)
633 VariantCopy(&rgVar[local], &This->list->data[i]);
635 if (fetched) *fetched = local;
636 This->pos = i;
638 return (local < celt) ? S_FALSE : S_OK;
641 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
643 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
645 TRACE("%p, %lu\n", iface, celt);
647 This->pos += celt;
648 if (This->pos >= This->list->count)
650 This->pos = This->list->count;
651 return S_FALSE;
654 return S_OK;
657 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
659 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
661 TRACE("(%p)\n", iface);
663 This->pos = 0;
664 return S_OK;
667 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
669 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
670 HRESULT hr;
672 TRACE("(%p,%p)\n", iface, ppEnum);
674 if (ppEnum == NULL)
675 return S_FALSE;
677 *ppEnum = NULL;
678 hr = create_list_enumerator(This->list, (LPVOID *)ppEnum);
679 if (FAILED(hr))
681 if (*ppEnum) IEnumVARIANT_Release(*ppEnum);
682 return hr;
685 return S_OK;
688 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
690 ListEnumerator_QueryInterface,
691 ListEnumerator_AddRef,
692 ListEnumerator_Release,
693 ListEnumerator_Next,
694 ListEnumerator_Skip,
695 ListEnumerator_Reset,
696 ListEnumerator_Clone
699 /* Create a list enumerator, placing the result in the pointer ppObj. */
700 static HRESULT create_list_enumerator(ListObject *list, void **ppObj)
702 ListEnumerator *object;
704 TRACE("(%p, %p)\n", list, ppObj);
706 object = msi_alloc(sizeof(ListEnumerator));
708 /* Set all the VTable references */
709 object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
710 object->ref = 1;
712 /* Store data that was passed */
713 object->pos = 0;
714 object->list = list;
715 if (list) IDispatch_AddRef(&list->autoobj.IDispatch_iface);
717 *ppObj = object;
718 return S_OK;
722 * Individual Object Invocation Functions
725 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
726 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
727 using DispGetParam/VariantChangeType. */
728 static HRESULT DispGetParam_CopyOnly(
729 DISPPARAMS *pdispparams, /* [in] Parameter list */
730 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
731 VARIANT *pvarResult) /* [out] Destination for resulting variant */
733 /* position is counted backwards */
734 UINT pos;
736 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
737 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
738 if (*position < pdispparams->cArgs) {
739 /* positional arg? */
740 pos = pdispparams->cArgs - *position - 1;
741 } else {
742 /* FIXME: is this how to handle named args? */
743 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
744 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
746 if (pos==pdispparams->cNamedArgs)
747 return DISP_E_PARAMNOTFOUND;
749 *position = pos;
750 return VariantCopyInd(pvarResult,
751 &pdispparams->rgvarg[pos]);
754 static HRESULT summaryinfo_invoke(
755 AutomationObject* This,
756 DISPID dispIdMember,
757 REFIID riid,
758 LCID lcid,
759 WORD wFlags,
760 DISPPARAMS* pDispParams,
761 VARIANT* pVarResult,
762 EXCEPINFO* pExcepInfo,
763 UINT* puArgErr)
765 UINT ret;
766 VARIANTARG varg0, varg1;
767 FILETIME ft, ftlocal;
768 SYSTEMTIME st;
769 HRESULT hr;
771 VariantInit(&varg0);
772 VariantInit(&varg1);
774 switch (dispIdMember)
776 case DISPID_SUMMARYINFO_PROPERTY:
777 if (wFlags & DISPATCH_PROPERTYGET)
779 UINT type;
780 INT value;
781 DWORD size = 0;
782 DATE date;
783 LPWSTR str;
785 static WCHAR szEmpty[] = L"";
787 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
788 if (FAILED(hr)) return hr;
789 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
790 &ft, szEmpty, &size);
791 if (ret != ERROR_SUCCESS &&
792 ret != ERROR_MORE_DATA)
794 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
795 return DISP_E_EXCEPTION;
798 switch (type)
800 case VT_EMPTY:
801 break;
803 case VT_I2:
804 case VT_I4:
805 V_VT(pVarResult) = VT_I4;
806 V_I4(pVarResult) = value;
807 break;
809 case VT_LPSTR:
810 if (!(str = msi_alloc(++size * sizeof(WCHAR))))
811 ERR("Out of memory\n");
812 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
813 NULL, str, &size)) != ERROR_SUCCESS)
814 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
815 else
817 V_VT(pVarResult) = VT_BSTR;
818 V_BSTR(pVarResult) = SysAllocString(str);
820 msi_free(str);
821 break;
823 case VT_FILETIME:
824 FileTimeToLocalFileTime(&ft, &ftlocal);
825 FileTimeToSystemTime(&ftlocal, &st);
826 SystemTimeToVariantTime(&st, &date);
828 V_VT(pVarResult) = VT_DATE;
829 V_DATE(pVarResult) = date;
830 break;
832 default:
833 ERR("Unhandled variant type %d\n", type);
836 else if (wFlags & DISPATCH_PROPERTYPUT)
838 UINT posValue = DISPID_PROPERTYPUT;
840 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
841 if (FAILED(hr)) return hr;
842 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
843 if (FAILED(hr))
845 *puArgErr = posValue;
846 return hr;
849 switch (V_VT(&varg1))
851 case VT_I2:
852 case VT_I4:
853 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
854 break;
856 case VT_DATE:
857 VariantTimeToSystemTime(V_DATE(&varg1), &st);
858 SystemTimeToFileTime(&st, &ftlocal);
859 LocalFileTimeToFileTime(&ftlocal, &ft);
860 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
861 break;
863 case VT_BSTR:
864 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
865 break;
867 default:
868 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
869 VariantClear(&varg1);
870 return DISP_E_EXCEPTION;
873 if (ret != ERROR_SUCCESS)
875 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
876 return DISP_E_EXCEPTION;
879 else return DISP_E_MEMBERNOTFOUND;
880 break;
882 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
883 if (wFlags & DISPATCH_PROPERTYGET) {
884 UINT count;
885 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
886 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
887 else
889 V_VT(pVarResult) = VT_I4;
890 V_I4(pVarResult) = count;
893 else return DISP_E_MEMBERNOTFOUND;
894 break;
896 default:
897 return DISP_E_MEMBERNOTFOUND;
900 VariantClear(&varg1);
901 VariantClear(&varg0);
903 return S_OK;
906 static HRESULT record_invoke(
907 AutomationObject* This,
908 DISPID dispIdMember,
909 REFIID riid,
910 LCID lcid,
911 WORD wFlags,
912 DISPPARAMS* pDispParams,
913 VARIANT* pVarResult,
914 EXCEPINFO* pExcepInfo,
915 UINT* puArgErr)
917 WCHAR *szString;
918 DWORD dwLen = 0;
919 UINT ret;
920 VARIANTARG varg0, varg1;
921 HRESULT hr;
923 VariantInit(&varg0);
924 VariantInit(&varg1);
926 switch (dispIdMember)
928 case DISPID_RECORD_FIELDCOUNT:
929 if (wFlags & DISPATCH_PROPERTYGET) {
930 V_VT(pVarResult) = VT_I4;
931 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
933 else return DISP_E_MEMBERNOTFOUND;
934 break;
936 case DISPID_RECORD_STRINGDATA:
937 if (wFlags & DISPATCH_PROPERTYGET) {
938 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
939 if (FAILED(hr)) return hr;
940 V_VT(pVarResult) = VT_BSTR;
941 V_BSTR(pVarResult) = NULL;
942 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
944 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
945 ERR("Out of memory\n");
946 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
947 V_BSTR(pVarResult) = SysAllocString(szString);
948 msi_free(szString);
950 if (ret != ERROR_SUCCESS)
951 ERR("MsiRecordGetString returned %d\n", ret);
952 } else if (wFlags & DISPATCH_PROPERTYPUT) {
953 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
954 if (FAILED(hr)) return hr;
955 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
956 if (FAILED(hr)) return hr;
957 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
959 VariantClear(&varg1);
960 ERR("MsiRecordSetString returned %d\n", ret);
961 return DISP_E_EXCEPTION;
964 else return DISP_E_MEMBERNOTFOUND;
965 break;
967 case DISPID_RECORD_INTEGERDATA:
968 if (wFlags & DISPATCH_PROPERTYGET) {
969 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
970 if (FAILED(hr)) return hr;
971 V_VT(pVarResult) = VT_I4;
972 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
973 } else if (wFlags & DISPATCH_PROPERTYPUT) {
974 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
975 if (FAILED(hr)) return hr;
976 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
977 if (FAILED(hr)) return hr;
978 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
980 ERR("MsiRecordSetInteger returned %d\n", ret);
981 return DISP_E_EXCEPTION;
984 else return DISP_E_MEMBERNOTFOUND;
985 break;
987 default:
988 return DISP_E_MEMBERNOTFOUND;
991 VariantClear(&varg1);
992 VariantClear(&varg0);
994 return S_OK;
997 static HRESULT create_record(MSIHANDLE msiHandle, IDispatch **disp)
999 AutomationObject *record;
1001 record = msi_alloc(sizeof(*record));
1002 if (!record) return E_OUTOFMEMORY;
1004 init_automation_object(record, msiHandle, Record_tid);
1006 *disp = &record->IDispatch_iface;
1008 return S_OK;
1011 static HRESULT list_invoke(
1012 AutomationObject* This,
1013 DISPID dispIdMember,
1014 REFIID riid,
1015 LCID lcid,
1016 WORD wFlags,
1017 DISPPARAMS* pDispParams,
1018 VARIANT* pVarResult,
1019 EXCEPINFO* pExcepInfo,
1020 UINT* puArgErr)
1022 ListObject *list = CONTAINING_RECORD(This, ListObject, autoobj);
1023 IUnknown *pUnk = NULL;
1024 HRESULT hr;
1026 switch (dispIdMember)
1028 case DISPID_LIST__NEWENUM:
1029 if (wFlags & DISPATCH_METHOD) {
1030 V_VT(pVarResult) = VT_UNKNOWN;
1031 if (SUCCEEDED(hr = create_list_enumerator(list, (LPVOID *)&pUnk)))
1032 V_UNKNOWN(pVarResult) = pUnk;
1033 else
1034 ERR("failed to create IEnumVARIANT object, hresult %#lx\n", hr);
1036 else return DISP_E_MEMBERNOTFOUND;
1037 break;
1039 case DISPID_LIST_ITEM:
1040 if (wFlags & DISPATCH_PROPERTYGET) {
1041 VARIANTARG index;
1043 VariantInit(&index);
1044 hr = DispGetParam(pDispParams, 0, VT_I4, &index, puArgErr);
1045 if (FAILED(hr)) return hr;
1046 if (V_I4(&index) < 0 || V_I4(&index) >= list->count)
1047 return DISP_E_BADINDEX;
1048 VariantCopy(pVarResult, &list->data[V_I4(&index)]);
1050 else return DISP_E_MEMBERNOTFOUND;
1051 break;
1053 case DISPID_LIST_COUNT:
1054 if (wFlags & DISPATCH_PROPERTYGET) {
1055 V_VT(pVarResult) = VT_I4;
1056 V_I4(pVarResult) = list->count;
1058 else return DISP_E_MEMBERNOTFOUND;
1059 break;
1061 default:
1062 return DISP_E_MEMBERNOTFOUND;
1065 return S_OK;
1068 static void list_free(AutomationObject *This)
1070 ListObject *list = CONTAINING_RECORD(This, ListObject, autoobj);
1071 int i;
1073 for (i = 0; i < list->count; i++)
1074 VariantClear(&list->data[i]);
1075 msi_free(list->data);
1078 static HRESULT get_products_count(const WCHAR *product, int *len)
1080 int i = 0;
1082 while (1)
1084 WCHAR dataW[GUID_SIZE];
1085 UINT ret;
1087 /* all or related only */
1088 if (product)
1089 ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1090 else
1091 ret = MsiEnumProductsW(i, dataW);
1093 if (ret == ERROR_NO_MORE_ITEMS) break;
1095 if (ret != ERROR_SUCCESS)
1096 return DISP_E_EXCEPTION;
1098 i++;
1101 *len = i;
1103 return S_OK;
1106 static HRESULT create_list(const WCHAR *product, IDispatch **dispatch)
1108 ListObject *list;
1109 HRESULT hr;
1110 int i;
1112 list = msi_alloc_zero(sizeof(ListObject));
1113 if (!list) return E_OUTOFMEMORY;
1115 init_automation_object(&list->autoobj, 0, StringList_tid);
1117 *dispatch = &list->autoobj.IDispatch_iface;
1119 hr = get_products_count(product, &list->count);
1120 if (hr != S_OK)
1122 IDispatch_Release(*dispatch);
1123 return hr;
1126 list->data = msi_alloc(list->count*sizeof(VARIANT));
1127 if (!list->data)
1129 IDispatch_Release(*dispatch);
1130 return E_OUTOFMEMORY;
1133 for (i = 0; i < list->count; i++)
1135 WCHAR dataW[GUID_SIZE];
1136 UINT ret;
1138 /* all or related only */
1139 if (product)
1140 ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1141 else
1142 ret = MsiEnumProductsW(i, dataW);
1144 if (ret == ERROR_NO_MORE_ITEMS) break;
1146 V_VT(&list->data[i]) = VT_BSTR;
1147 V_BSTR(&list->data[i]) = SysAllocString(dataW);
1150 return S_OK;
1153 static HRESULT view_invoke(
1154 AutomationObject* This,
1155 DISPID dispIdMember,
1156 REFIID riid,
1157 LCID lcid,
1158 WORD wFlags,
1159 DISPPARAMS* pDispParams,
1160 VARIANT* pVarResult,
1161 EXCEPINFO* pExcepInfo,
1162 UINT* puArgErr)
1164 MSIHANDLE msiHandle;
1165 UINT ret;
1166 VARIANTARG varg0, varg1;
1167 HRESULT hr;
1169 VariantInit(&varg0);
1170 VariantInit(&varg1);
1172 switch (dispIdMember)
1174 case DISPID_VIEW_EXECUTE:
1175 if (wFlags & DISPATCH_METHOD)
1177 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1178 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1179 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1180 else
1181 MsiViewExecute(This->msiHandle, 0);
1183 else return DISP_E_MEMBERNOTFOUND;
1184 break;
1186 case DISPID_VIEW_FETCH:
1187 if (wFlags & DISPATCH_METHOD)
1189 V_VT(pVarResult) = VT_DISPATCH;
1190 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1192 if (FAILED(hr = create_record(msiHandle, &V_DISPATCH(pVarResult))))
1193 ERR("failed to create Record object, hresult %#lx\n", hr);
1195 else if (ret == ERROR_NO_MORE_ITEMS)
1196 V_DISPATCH(pVarResult) = NULL;
1197 else
1199 ERR("MsiViewFetch returned %d\n", ret);
1200 return DISP_E_EXCEPTION;
1203 else return DISP_E_MEMBERNOTFOUND;
1204 break;
1206 case DISPID_VIEW_MODIFY:
1207 if (wFlags & DISPATCH_METHOD)
1209 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1210 if (FAILED(hr)) return hr;
1211 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1212 if (FAILED(hr)) return hr;
1213 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1214 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1216 VariantClear(&varg1);
1217 ERR("MsiViewModify returned %d\n", ret);
1218 return DISP_E_EXCEPTION;
1221 else return DISP_E_MEMBERNOTFOUND;
1222 break;
1224 case DISPID_VIEW_CLOSE:
1225 if (wFlags & DISPATCH_METHOD)
1227 MsiViewClose(This->msiHandle);
1229 else return DISP_E_MEMBERNOTFOUND;
1230 break;
1232 default:
1233 return DISP_E_MEMBERNOTFOUND;
1236 VariantClear(&varg1);
1237 VariantClear(&varg0);
1239 return S_OK;
1242 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
1243 DISPPARAMS* pDispParams,
1244 VARIANT* pVarResult,
1245 EXCEPINFO* pExcepInfo,
1246 UINT* puArgErr)
1248 if (!(wFlags & DISPATCH_METHOD))
1249 return DISP_E_MEMBERNOTFOUND;
1251 FIXME("\n");
1253 VariantInit(pVarResult);
1254 return S_OK;
1257 HRESULT database_invoke(
1258 AutomationObject* This,
1259 DISPID dispIdMember,
1260 REFIID riid,
1261 LCID lcid,
1262 WORD wFlags,
1263 DISPPARAMS* pDispParams,
1264 VARIANT* pVarResult,
1265 EXCEPINFO* pExcepInfo,
1266 UINT* puArgErr)
1268 IDispatch *dispatch = NULL;
1269 MSIHANDLE msiHandle;
1270 UINT ret;
1271 VARIANTARG varg0, varg1;
1272 HRESULT hr;
1274 VariantInit(&varg0);
1275 VariantInit(&varg1);
1277 switch (dispIdMember)
1279 case DISPID_DATABASE_SUMMARYINFORMATION:
1280 if (wFlags & DISPATCH_PROPERTYGET)
1282 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1283 if (FAILED(hr))
1284 V_I4(&varg0) = 0;
1286 V_VT(pVarResult) = VT_DISPATCH;
1287 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1289 hr = create_summaryinfo(msiHandle, &dispatch);
1290 if (SUCCEEDED(hr))
1291 V_DISPATCH(pVarResult) = dispatch;
1292 else
1293 ERR("failed to create SummaryInfo object: %#lx\n", hr);
1295 else
1297 ERR("MsiGetSummaryInformation returned %d\n", ret);
1298 return DISP_E_EXCEPTION;
1301 else return DISP_E_MEMBERNOTFOUND;
1302 break;
1304 case DISPID_DATABASE_OPENVIEW:
1305 if (wFlags & DISPATCH_METHOD)
1307 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1308 if (FAILED(hr)) return hr;
1309 V_VT(pVarResult) = VT_DISPATCH;
1310 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1312 if (SUCCEEDED(hr = create_view(msiHandle, &dispatch)))
1313 V_DISPATCH(pVarResult) = dispatch;
1314 else
1315 ERR("failed to create View object, hresult %#lx\n", hr);
1317 else
1319 VariantClear(&varg0);
1320 ERR("MsiDatabaseOpenView returned %d\n", ret);
1321 return DISP_E_EXCEPTION;
1324 else return DISP_E_MEMBERNOTFOUND;
1325 break;
1327 case DISPID_INSTALLER_LASTERRORRECORD:
1328 return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
1329 pVarResult, pExcepInfo,
1330 puArgErr);
1332 default:
1333 return DISP_E_MEMBERNOTFOUND;
1336 VariantClear(&varg1);
1337 VariantClear(&varg0);
1339 return S_OK;
1342 static HRESULT session_invoke(
1343 AutomationObject* This,
1344 DISPID dispIdMember,
1345 REFIID riid,
1346 LCID lcid,
1347 WORD wFlags,
1348 DISPPARAMS* pDispParams,
1349 VARIANT* pVarResult,
1350 EXCEPINFO* pExcepInfo,
1351 UINT* puArgErr)
1353 SessionObject *session = CONTAINING_RECORD(This, SessionObject, autoobj);
1354 WCHAR *szString;
1355 DWORD dwLen = 0;
1356 MSIHANDLE msiHandle;
1357 LANGID langId;
1358 UINT ret;
1359 INSTALLSTATE iInstalled, iAction;
1360 VARIANTARG varg0, varg1;
1361 HRESULT hr;
1363 VariantInit(&varg0);
1364 VariantInit(&varg1);
1366 switch (dispIdMember)
1368 case DISPID_SESSION_INSTALLER:
1369 if (wFlags & DISPATCH_PROPERTYGET) {
1370 V_VT(pVarResult) = VT_DISPATCH;
1371 IDispatch_AddRef(session->installer);
1372 V_DISPATCH(pVarResult) = session->installer;
1374 else return DISP_E_MEMBERNOTFOUND;
1375 break;
1377 case DISPID_SESSION_PROPERTY:
1378 if (wFlags & DISPATCH_PROPERTYGET) {
1379 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1380 if (FAILED(hr)) return hr;
1381 V_VT(pVarResult) = VT_BSTR;
1382 V_BSTR(pVarResult) = NULL;
1383 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1385 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1386 ERR("Out of memory\n");
1387 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1388 V_BSTR(pVarResult) = SysAllocString(szString);
1389 msi_free(szString);
1391 if (ret != ERROR_SUCCESS)
1392 ERR("MsiGetProperty returned %d\n", ret);
1393 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1394 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1395 if (FAILED(hr)) return hr;
1396 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1397 if (FAILED(hr)) {
1398 VariantClear(&varg0);
1399 return hr;
1401 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1403 VariantClear(&varg0);
1404 VariantClear(&varg1);
1405 ERR("MsiSetProperty returned %d\n", ret);
1406 return DISP_E_EXCEPTION;
1409 else return DISP_E_MEMBERNOTFOUND;
1410 break;
1412 case DISPID_SESSION_LANGUAGE:
1413 if (wFlags & DISPATCH_PROPERTYGET) {
1414 langId = MsiGetLanguage(This->msiHandle);
1415 V_VT(pVarResult) = VT_I4;
1416 V_I4(pVarResult) = langId;
1418 else return DISP_E_MEMBERNOTFOUND;
1419 break;
1421 case DISPID_SESSION_MODE:
1422 if (wFlags & DISPATCH_PROPERTYGET) {
1423 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1424 if (FAILED(hr)) return hr;
1425 V_VT(pVarResult) = VT_BOOL;
1426 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0)) ? VARIANT_TRUE : VARIANT_FALSE;
1427 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1428 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1429 if (FAILED(hr)) return hr;
1430 hr = DispGetParam(pDispParams, 1, VT_BOOL, &varg1, puArgErr);
1431 if (FAILED(hr)) return hr;
1432 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1434 ERR("MsiSetMode returned %d\n", ret);
1435 return DISP_E_EXCEPTION;
1438 else return DISP_E_MEMBERNOTFOUND;
1439 break;
1441 case DISPID_SESSION_DATABASE:
1442 if (wFlags & DISPATCH_PROPERTYGET) {
1443 V_VT(pVarResult) = VT_DISPATCH;
1444 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1446 IDispatch *dispatch;
1448 if (SUCCEEDED(hr = create_database(msiHandle, &dispatch)))
1449 V_DISPATCH(pVarResult) = dispatch;
1450 else
1451 ERR("failed to create Database object, hresult %#lx\n", hr);
1453 else
1455 ERR("MsiGetActiveDatabase failed\n");
1456 return DISP_E_EXCEPTION;
1459 else return DISP_E_MEMBERNOTFOUND;
1460 break;
1462 case DISPID_SESSION_DOACTION:
1463 if (wFlags & DISPATCH_METHOD) {
1464 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1465 if (FAILED(hr)) return hr;
1466 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1467 V_VT(pVarResult) = VT_I4;
1468 switch (ret)
1470 case ERROR_FUNCTION_NOT_CALLED:
1471 V_I4(pVarResult) = msiDoActionStatusNoAction;
1472 break;
1473 case ERROR_SUCCESS:
1474 V_I4(pVarResult) = msiDoActionStatusSuccess;
1475 break;
1476 case ERROR_INSTALL_USEREXIT:
1477 V_I4(pVarResult) = msiDoActionStatusUserExit;
1478 break;
1479 case ERROR_INSTALL_FAILURE:
1480 V_I4(pVarResult) = msiDoActionStatusFailure;
1481 break;
1482 case ERROR_INSTALL_SUSPEND:
1483 V_I4(pVarResult) = msiDoActionStatusSuspend;
1484 break;
1485 case ERROR_MORE_DATA:
1486 V_I4(pVarResult) = msiDoActionStatusFinished;
1487 break;
1488 case ERROR_INVALID_HANDLE_STATE:
1489 V_I4(pVarResult) = msiDoActionStatusWrongState;
1490 break;
1491 case ERROR_INVALID_DATA:
1492 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1493 break;
1494 default:
1495 VariantClear(&varg0);
1496 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1497 return DISP_E_EXCEPTION;
1500 else return DISP_E_MEMBERNOTFOUND;
1501 break;
1503 case DISPID_SESSION_EVALUATECONDITION:
1504 if (wFlags & DISPATCH_METHOD) {
1505 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1506 if (FAILED(hr)) return hr;
1507 V_VT(pVarResult) = VT_I4;
1508 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1510 else return DISP_E_MEMBERNOTFOUND;
1511 break;
1513 case DISPID_SESSION_MESSAGE:
1514 if(!(wFlags & DISPATCH_METHOD))
1515 return DISP_E_MEMBERNOTFOUND;
1517 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1518 if (FAILED(hr)) return hr;
1519 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1520 if (FAILED(hr)) return hr;
1522 V_VT(pVarResult) = VT_I4;
1523 V_I4(pVarResult) =
1524 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
1525 break;
1527 case DISPID_SESSION_SETINSTALLLEVEL:
1528 if (wFlags & DISPATCH_METHOD) {
1529 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1530 if (FAILED(hr)) return hr;
1531 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1533 ERR("MsiSetInstallLevel returned %d\n", ret);
1534 return DISP_E_EXCEPTION;
1537 else return DISP_E_MEMBERNOTFOUND;
1538 break;
1540 case DISPID_SESSION_FEATURECURRENTSTATE:
1541 if (wFlags & DISPATCH_PROPERTYGET) {
1542 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1543 if (FAILED(hr)) return hr;
1544 V_VT(pVarResult) = VT_I4;
1545 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1546 V_I4(pVarResult) = iInstalled;
1547 else
1549 ERR("MsiGetFeatureState returned %d\n", ret);
1550 V_I4(pVarResult) = msiInstallStateUnknown;
1553 else return DISP_E_MEMBERNOTFOUND;
1554 break;
1556 case DISPID_SESSION_FEATUREREQUESTSTATE:
1557 if (wFlags & DISPATCH_PROPERTYGET) {
1558 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1559 if (FAILED(hr)) return hr;
1560 V_VT(pVarResult) = VT_I4;
1561 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1562 V_I4(pVarResult) = iAction;
1563 else
1565 ERR("MsiGetFeatureState returned %d\n", ret);
1566 V_I4(pVarResult) = msiInstallStateUnknown;
1568 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1569 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1570 if (FAILED(hr)) return hr;
1571 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1572 if (FAILED(hr)) {
1573 VariantClear(&varg0);
1574 return hr;
1576 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1578 VariantClear(&varg0);
1579 ERR("MsiSetFeatureState returned %d\n", ret);
1580 return DISP_E_EXCEPTION;
1583 else return DISP_E_MEMBERNOTFOUND;
1584 break;
1586 default:
1587 return DISP_E_MEMBERNOTFOUND;
1590 VariantClear(&varg1);
1591 VariantClear(&varg0);
1593 return S_OK;
1596 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1597 * registry value type. Used by Installer::RegistryValue. */
1598 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1600 WCHAR *szString = (WCHAR *)lpData;
1601 LPWSTR szNewString = NULL;
1602 DWORD dwNewSize = 0;
1603 int idx;
1605 switch (dwType)
1607 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1608 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1609 idx = (dwSize/sizeof(WCHAR))-1;
1610 while (idx >= 0 && !szString[idx]) idx--;
1611 for (; idx >= 0; idx--)
1612 if (!szString[idx]) szString[idx] = '\n';
1613 /* fall through */
1614 case REG_SZ:
1615 V_VT(pVarResult) = VT_BSTR;
1616 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1617 break;
1619 case REG_EXPAND_SZ:
1620 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1621 ERR("ExpandEnvironmentStrings returned error %lu\n", GetLastError());
1622 else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1623 ERR("Out of memory\n");
1624 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1625 ERR("ExpandEnvironmentStrings returned error %lu\n", GetLastError());
1626 else
1628 V_VT(pVarResult) = VT_BSTR;
1629 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1631 msi_free(szNewString);
1632 break;
1634 case REG_DWORD:
1635 V_VT(pVarResult) = VT_I4;
1636 V_I4(pVarResult) = *((DWORD *)lpData);
1637 break;
1639 case REG_QWORD:
1640 V_VT(pVarResult) = VT_BSTR;
1641 V_BSTR(pVarResult) = SysAllocString(L"(REG_\?\?)"); /* Weird string, don't know why native returns it */
1642 break;
1644 case REG_BINARY:
1645 V_VT(pVarResult) = VT_BSTR;
1646 V_BSTR(pVarResult) = SysAllocString(L"(REG_BINARY)");
1647 break;
1649 case REG_NONE:
1650 V_VT(pVarResult) = VT_EMPTY;
1651 break;
1653 default:
1654 FIXME("Unhandled registry value type %lu\n", dwType);
1658 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1659 DISPPARAMS* pDispParams,
1660 VARIANT* pVarResult,
1661 EXCEPINFO* pExcepInfo,
1662 UINT* puArgErr)
1664 HRESULT hr;
1665 VARIANTARG varg0;
1666 MSIHANDLE hrec;
1668 if (!(wFlags & DISPATCH_METHOD))
1669 return DISP_E_MEMBERNOTFOUND;
1671 VariantInit(&varg0);
1672 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1673 if (FAILED(hr))
1674 return hr;
1676 V_VT(pVarResult) = VT_DISPATCH;
1678 hrec = MsiCreateRecord(V_I4(&varg0));
1679 if (!hrec)
1680 return DISP_E_EXCEPTION;
1682 return create_record(hrec, &V_DISPATCH(pVarResult));
1685 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1686 WORD wFlags,
1687 DISPPARAMS* pDispParams,
1688 VARIANT* pVarResult,
1689 EXCEPINFO* pExcepInfo,
1690 UINT* puArgErr)
1692 UINT ret;
1693 HRESULT hr;
1694 MSIHANDLE hpkg;
1695 IDispatch* dispatch;
1696 VARIANTARG varg0, varg1;
1698 if (!(wFlags & DISPATCH_METHOD))
1699 return DISP_E_MEMBERNOTFOUND;
1701 if (pDispParams->cArgs == 0)
1702 return DISP_E_TYPEMISMATCH;
1704 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1705 return DISP_E_TYPEMISMATCH;
1707 VariantInit(&varg0);
1708 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1709 if (FAILED(hr))
1710 return hr;
1712 VariantInit(&varg1);
1713 if (pDispParams->cArgs == 2)
1715 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1716 if (FAILED(hr))
1717 goto done;
1719 else
1721 V_VT(&varg1) = VT_I4;
1722 V_I4(&varg1) = 0;
1725 V_VT(pVarResult) = VT_DISPATCH;
1727 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1728 if (ret != ERROR_SUCCESS)
1730 hr = DISP_E_EXCEPTION;
1731 goto done;
1734 hr = create_session(hpkg, &This->IDispatch_iface, &dispatch);
1735 if (SUCCEEDED(hr))
1736 V_DISPATCH(pVarResult) = dispatch;
1738 done:
1739 VariantClear(&varg0);
1740 VariantClear(&varg1);
1741 return hr;
1744 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1745 DISPPARAMS* pDispParams,
1746 VARIANT* pVarResult,
1747 EXCEPINFO* pExcepInfo,
1748 UINT* puArgErr)
1750 HRESULT hr;
1751 VARIANTARG varg0;
1753 if (!(wFlags & DISPATCH_METHOD))
1754 return DISP_E_MEMBERNOTFOUND;
1756 VariantInit(&varg0);
1757 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1758 if (FAILED(hr))
1759 return hr;
1761 FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1763 VariantInit(pVarResult);
1765 VariantClear(&varg0);
1766 return S_OK;
1769 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1770 DISPPARAMS* pDispParams,
1771 VARIANT* pVarResult,
1772 EXCEPINFO* pExcepInfo,
1773 UINT* puArgErr)
1775 UINT ret;
1776 HRESULT hr;
1777 MSIHANDLE hdb;
1778 IDispatch* dispatch;
1779 VARIANTARG varg0, varg1;
1781 if (!(wFlags & DISPATCH_METHOD))
1782 return DISP_E_MEMBERNOTFOUND;
1784 VariantInit(&varg0);
1785 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1786 if (FAILED(hr))
1787 return hr;
1789 VariantInit(&varg1);
1790 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1791 if (FAILED(hr))
1792 goto done;
1794 V_VT(pVarResult) = VT_DISPATCH;
1796 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1797 if (ret != ERROR_SUCCESS)
1799 hr = DISP_E_EXCEPTION;
1800 goto done;
1803 hr = create_database(hdb, &dispatch);
1804 if (SUCCEEDED(hr))
1805 V_DISPATCH(pVarResult) = dispatch;
1807 done:
1808 VariantClear(&varg0);
1809 VariantClear(&varg1);
1810 return hr;
1813 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1814 DISPPARAMS* pDispParams,
1815 VARIANT* pVarResult,
1816 EXCEPINFO* pExcepInfo,
1817 UINT* puArgErr)
1819 UINT ret;
1820 HRESULT hr;
1821 MSIHANDLE hsuminfo;
1822 IDispatch *dispatch;
1823 VARIANTARG varg0, varg1;
1825 if (!(wFlags & DISPATCH_PROPERTYGET))
1826 return DISP_E_MEMBERNOTFOUND;
1828 VariantInit(&varg1);
1829 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1830 if (FAILED(hr))
1831 return hr;
1833 VariantInit(&varg0);
1834 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1835 if (FAILED(hr))
1836 return hr;
1838 ret = MsiGetSummaryInformationW(0, V_BSTR(&varg0), V_I4(&varg1), &hsuminfo);
1839 VariantClear(&varg0);
1840 if (ret != ERROR_SUCCESS)
1841 return DISP_E_EXCEPTION;
1843 hr = create_summaryinfo(hsuminfo, &dispatch);
1844 if (FAILED(hr))
1845 return hr;
1847 V_VT(pVarResult) = VT_DISPATCH;
1848 V_DISPATCH(pVarResult) = dispatch;
1849 return S_OK;
1852 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1853 DISPPARAMS* pDispParams,
1854 VARIANT* pVarResult,
1855 EXCEPINFO* pExcepInfo,
1856 UINT* puArgErr)
1858 HRESULT hr;
1859 VARIANTARG varg0;
1860 INSTALLUILEVEL ui;
1862 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1863 return DISP_E_MEMBERNOTFOUND;
1865 if (wFlags & DISPATCH_PROPERTYPUT)
1867 VariantInit(&varg0);
1868 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1869 if (FAILED(hr))
1870 return hr;
1872 ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1873 if (ui == INSTALLUILEVEL_NOCHANGE)
1874 return DISP_E_EXCEPTION;
1876 else if (wFlags & DISPATCH_PROPERTYGET)
1878 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1879 if (ui == INSTALLUILEVEL_NOCHANGE)
1880 return DISP_E_EXCEPTION;
1882 V_VT(pVarResult) = VT_I4;
1883 V_I4(pVarResult) = ui;
1886 return S_OK;
1889 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1890 DISPPARAMS* pDispParams,
1891 VARIANT* pVarResult,
1892 EXCEPINFO* pExcepInfo,
1893 UINT* puArgErr)
1895 if (!(wFlags & DISPATCH_METHOD))
1896 return DISP_E_MEMBERNOTFOUND;
1898 FIXME("\n");
1900 VariantInit(pVarResult);
1901 return S_OK;
1904 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1905 DISPPARAMS* pDispParams,
1906 VARIANT* pVarResult,
1907 EXCEPINFO* pExcepInfo,
1908 UINT* puArgErr)
1910 UINT ret;
1911 HRESULT hr;
1912 VARIANTARG varg0, varg1;
1914 if (!(wFlags & DISPATCH_METHOD))
1915 return DISP_E_MEMBERNOTFOUND;
1917 VariantInit(&varg0);
1918 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1919 if (FAILED(hr))
1920 return hr;
1922 VariantInit(&varg1);
1923 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1924 if (FAILED(hr))
1925 goto done;
1927 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1928 if (ret != ERROR_SUCCESS)
1930 hr = DISP_E_EXCEPTION;
1931 goto done;
1934 done:
1935 VariantClear(&varg0);
1936 VariantClear(&varg1);
1937 return hr;
1940 static HRESULT InstallerImpl_Version(WORD wFlags,
1941 VARIANT* pVarResult,
1942 EXCEPINFO* pExcepInfo,
1943 UINT* puArgErr)
1945 HRESULT hr;
1946 DLLVERSIONINFO verinfo;
1947 WCHAR version[MAX_PATH];
1949 if (!(wFlags & DISPATCH_PROPERTYGET))
1950 return DISP_E_MEMBERNOTFOUND;
1952 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1953 hr = DllGetVersion(&verinfo);
1954 if (FAILED(hr))
1955 return hr;
1957 swprintf(version, ARRAY_SIZE(version), L"%d.%d.%d.%d", verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1958 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1960 V_VT(pVarResult) = VT_BSTR;
1961 V_BSTR(pVarResult) = SysAllocString(version);
1962 return S_OK;
1965 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1966 DISPPARAMS* pDispParams,
1967 VARIANT* pVarResult,
1968 EXCEPINFO* pExcepInfo,
1969 UINT* puArgErr)
1971 if (!(wFlags & DISPATCH_METHOD))
1972 return DISP_E_MEMBERNOTFOUND;
1974 FIXME("\n");
1976 VariantInit(pVarResult);
1977 return S_OK;
1980 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1981 DISPPARAMS* pDispParams,
1982 VARIANT* pVarResult,
1983 EXCEPINFO* pExcepInfo,
1984 UINT* puArgErr)
1986 UINT ret;
1987 HKEY hkey = NULL;
1988 HRESULT hr;
1989 UINT posValue;
1990 DWORD type, size;
1991 LPWSTR szString = NULL;
1992 VARIANTARG varg0, varg1, varg2;
1994 if (!(wFlags & DISPATCH_METHOD))
1995 return DISP_E_MEMBERNOTFOUND;
1997 VariantInit(&varg0);
1998 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1999 if (FAILED(hr))
2000 return hr;
2002 VariantInit(&varg1);
2003 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2004 if (FAILED(hr))
2005 goto done;
2007 /* Save valuePos so we can save puArgErr if we are unable to do our type
2008 * conversions.
2010 posValue = 2;
2011 VariantInit(&varg2);
2012 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
2013 if (FAILED(hr))
2014 goto done;
2016 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
2017 V_I4(&varg0) <= REG_INDEX_DYN_DATA)
2019 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
2022 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
2024 /* Only VT_EMPTY case can do anything if the key doesn't exist. */
2025 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
2027 hr = DISP_E_BADINDEX;
2028 goto done;
2031 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
2032 switch (V_VT(&varg2))
2034 /* Return VT_BOOL clarifying whether registry key exists or not. */
2035 case VT_EMPTY:
2036 V_VT(pVarResult) = VT_BOOL;
2037 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS) ? VARIANT_TRUE : VARIANT_FALSE;
2038 break;
2040 /* Return the value of specified key if it exists. */
2041 case VT_BSTR:
2042 ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
2043 NULL, NULL, NULL, &size);
2044 if (ret != ERROR_SUCCESS)
2046 hr = DISP_E_BADINDEX;
2047 goto done;
2050 szString = msi_alloc(size);
2051 if (!szString)
2053 hr = E_OUTOFMEMORY;
2054 goto done;
2057 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
2058 &type, (LPBYTE)szString, &size);
2059 if (ret != ERROR_SUCCESS)
2061 msi_free(szString);
2062 hr = DISP_E_BADINDEX;
2063 goto done;
2066 variant_from_registry_value(pVarResult, type,
2067 (LPBYTE)szString, size);
2068 msi_free(szString);
2069 break;
2071 /* Try to make it into VT_I4, can use VariantChangeType for this. */
2072 default:
2073 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
2074 if (FAILED(hr))
2076 if (hr == DISP_E_TYPEMISMATCH)
2077 *puArgErr = posValue;
2079 goto done;
2082 /* Retrieve class name or maximum value name or subkey name size. */
2083 if (!V_I4(&varg2))
2084 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
2085 NULL, NULL, NULL, NULL, NULL, NULL);
2086 else if (V_I4(&varg2) > 0)
2087 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
2088 NULL, NULL, &size, NULL, NULL, NULL);
2089 else /* V_I4(&varg2) < 0 */
2090 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
2091 NULL, NULL, NULL, NULL, NULL, NULL);
2093 if (ret != ERROR_SUCCESS)
2094 goto done;
2096 szString = msi_alloc(++size * sizeof(WCHAR));
2097 if (!szString)
2099 hr = E_OUTOFMEMORY;
2100 goto done;
2103 if (!V_I4(&varg2))
2104 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
2105 NULL, NULL, NULL, NULL, NULL, NULL);
2106 else if (V_I4(&varg2) > 0)
2107 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
2108 &size, 0, 0, NULL, NULL);
2109 else /* V_I4(&varg2) < 0 */
2110 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
2112 if (ret == ERROR_SUCCESS)
2114 V_VT(pVarResult) = VT_BSTR;
2115 V_BSTR(pVarResult) = SysAllocString(szString);
2118 msi_free(szString);
2121 done:
2122 VariantClear(&varg0);
2123 VariantClear(&varg1);
2124 VariantClear(&varg2);
2125 RegCloseKey(hkey);
2126 return hr;
2129 static HRESULT InstallerImpl_Environment(WORD wFlags,
2130 DISPPARAMS* pDispParams,
2131 VARIANT* pVarResult,
2132 EXCEPINFO* pExcepInfo,
2133 UINT* puArgErr)
2135 if (!(wFlags & DISPATCH_METHOD))
2136 return DISP_E_MEMBERNOTFOUND;
2138 FIXME("\n");
2140 VariantInit(pVarResult);
2141 return S_OK;
2144 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2145 DISPPARAMS* pDispParams,
2146 VARIANT* pVarResult,
2147 EXCEPINFO* pExcepInfo,
2148 UINT* puArgErr)
2150 if (!(wFlags & DISPATCH_METHOD))
2151 return DISP_E_MEMBERNOTFOUND;
2153 FIXME("\n");
2155 VariantInit(pVarResult);
2156 return S_OK;
2159 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2160 DISPPARAMS* pDispParams,
2161 VARIANT* pVarResult,
2162 EXCEPINFO* pExcepInfo,
2163 UINT* puArgErr)
2165 if (!(wFlags & DISPATCH_METHOD))
2166 return DISP_E_MEMBERNOTFOUND;
2168 FIXME("\n");
2170 VariantInit(pVarResult);
2171 return S_OK;
2174 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2175 DISPPARAMS* pDispParams,
2176 VARIANT* pVarResult,
2177 EXCEPINFO* pExcepInfo,
2178 UINT* puArgErr)
2180 if (!(wFlags & DISPATCH_METHOD))
2181 return DISP_E_MEMBERNOTFOUND;
2183 FIXME("\n");
2185 VariantInit(pVarResult);
2186 return S_OK;
2189 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2190 DISPPARAMS* pDispParams,
2191 VARIANT* pVarResult,
2192 EXCEPINFO* pExcepInfo,
2193 UINT* puArgErr)
2195 HRESULT hr;
2196 VARIANTARG varg0;
2198 if (!(wFlags & DISPATCH_PROPERTYGET))
2199 return DISP_E_MEMBERNOTFOUND;
2201 VariantInit(&varg0);
2202 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2203 if (FAILED(hr))
2204 return hr;
2206 V_VT(pVarResult) = VT_I4;
2207 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2209 VariantClear(&varg0);
2210 return S_OK;
2213 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2214 DISPPARAMS* pDispParams,
2215 VARIANT* pVarResult,
2216 EXCEPINFO* pExcepInfo,
2217 UINT* puArgErr)
2219 UINT ret;
2220 HRESULT hr;
2221 DWORD size;
2222 LPWSTR str = NULL;
2223 VARIANTARG varg0, varg1;
2225 if (!(wFlags & DISPATCH_PROPERTYGET))
2226 return DISP_E_MEMBERNOTFOUND;
2228 VariantInit(&varg0);
2229 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2230 if (FAILED(hr))
2231 return hr;
2233 VariantInit(&varg1);
2234 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2235 if (FAILED(hr))
2236 goto done;
2238 V_VT(pVarResult) = VT_BSTR;
2239 V_BSTR(pVarResult) = NULL;
2241 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2242 if (ret != ERROR_SUCCESS)
2244 hr = DISP_E_EXCEPTION;
2245 goto done;
2248 str = msi_alloc(++size * sizeof(WCHAR));
2249 if (!str)
2251 hr = E_OUTOFMEMORY;
2252 goto done;
2255 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2256 if (ret != ERROR_SUCCESS)
2258 hr = DISP_E_EXCEPTION;
2259 goto done;
2262 V_BSTR(pVarResult) = SysAllocString(str);
2263 hr = S_OK;
2265 done:
2266 msi_free(str);
2267 VariantClear(&varg0);
2268 VariantClear(&varg1);
2269 return hr;
2272 static HRESULT InstallerImpl_Products(WORD flags,
2273 DISPPARAMS* pDispParams,
2274 VARIANT* result,
2275 EXCEPINFO* pExcepInfo,
2276 UINT* puArgErr)
2278 IDispatch *dispatch;
2279 HRESULT hr;
2281 if (!(flags & DISPATCH_PROPERTYGET))
2282 return DISP_E_MEMBERNOTFOUND;
2284 hr = create_list(NULL, &dispatch);
2285 if (FAILED(hr))
2286 return hr;
2288 V_VT(result) = VT_DISPATCH;
2289 V_DISPATCH(result) = dispatch;
2291 return hr;
2294 static HRESULT InstallerImpl_RelatedProducts(WORD flags,
2295 DISPPARAMS* pDispParams,
2296 VARIANT* result,
2297 EXCEPINFO* pExcepInfo,
2298 UINT* puArgErr)
2300 IDispatch* dispatch;
2301 VARIANTARG related;
2302 HRESULT hr;
2304 if (!(flags & DISPATCH_PROPERTYGET))
2305 return DISP_E_MEMBERNOTFOUND;
2307 VariantInit(&related);
2308 hr = DispGetParam(pDispParams, 0, VT_BSTR, &related, puArgErr);
2309 if (FAILED(hr))
2310 return hr;
2312 hr = create_list(V_BSTR(&related), &dispatch);
2313 VariantClear(&related);
2315 V_VT(result) = VT_DISPATCH;
2316 V_DISPATCH(result) = dispatch;
2318 return hr;
2321 static HRESULT installer_invoke(
2322 AutomationObject* This,
2323 DISPID dispIdMember,
2324 REFIID riid,
2325 LCID lcid,
2326 WORD wFlags,
2327 DISPPARAMS* pDispParams,
2328 VARIANT* pVarResult,
2329 EXCEPINFO* pExcepInfo,
2330 UINT* puArgErr)
2332 switch (dispIdMember)
2334 case DISPID_INSTALLER_CREATERECORD:
2335 return InstallerImpl_CreateRecord(wFlags, pDispParams,
2336 pVarResult, pExcepInfo, puArgErr);
2338 case DISPID_INSTALLER_OPENPACKAGE:
2339 return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2340 pVarResult, pExcepInfo, puArgErr);
2342 case DISPID_INSTALLER_OPENPRODUCT:
2343 return InstallerImpl_OpenProduct(wFlags, pDispParams,
2344 pVarResult, pExcepInfo, puArgErr);
2346 case DISPID_INSTALLER_OPENDATABASE:
2347 return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2348 pVarResult, pExcepInfo, puArgErr);
2350 case DISPID_INSTALLER_SUMMARYINFORMATION:
2351 return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2352 pVarResult, pExcepInfo,
2353 puArgErr);
2355 case DISPID_INSTALLER_UILEVEL:
2356 return InstallerImpl_UILevel(wFlags, pDispParams,
2357 pVarResult, pExcepInfo, puArgErr);
2359 case DISPID_INSTALLER_ENABLELOG:
2360 return InstallerImpl_EnableLog(wFlags, pDispParams,
2361 pVarResult, pExcepInfo, puArgErr);
2363 case DISPID_INSTALLER_INSTALLPRODUCT:
2364 return InstallerImpl_InstallProduct(wFlags, pDispParams,
2365 pVarResult, pExcepInfo,
2366 puArgErr);
2368 case DISPID_INSTALLER_VERSION:
2369 return InstallerImpl_Version(wFlags, pVarResult,
2370 pExcepInfo, puArgErr);
2372 case DISPID_INSTALLER_LASTERRORRECORD:
2373 return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2374 pVarResult, pExcepInfo,
2375 puArgErr);
2377 case DISPID_INSTALLER_REGISTRYVALUE:
2378 return InstallerImpl_RegistryValue(wFlags, pDispParams,
2379 pVarResult, pExcepInfo,
2380 puArgErr);
2382 case DISPID_INSTALLER_ENVIRONMENT:
2383 return InstallerImpl_Environment(wFlags, pDispParams,
2384 pVarResult, pExcepInfo, puArgErr);
2386 case DISPID_INSTALLER_FILEATTRIBUTES:
2387 return InstallerImpl_FileAttributes(wFlags, pDispParams,
2388 pVarResult, pExcepInfo,
2389 puArgErr);
2391 case DISPID_INSTALLER_FILESIZE:
2392 return InstallerImpl_FileSize(wFlags, pDispParams,
2393 pVarResult, pExcepInfo, puArgErr);
2395 case DISPID_INSTALLER_FILEVERSION:
2396 return InstallerImpl_FileVersion(wFlags, pDispParams,
2397 pVarResult, pExcepInfo, puArgErr);
2399 case DISPID_INSTALLER_PRODUCTSTATE:
2400 return InstallerImpl_ProductState(wFlags, pDispParams,
2401 pVarResult, pExcepInfo, puArgErr);
2403 case DISPID_INSTALLER_PRODUCTINFO:
2404 return InstallerImpl_ProductInfo(wFlags, pDispParams,
2405 pVarResult, pExcepInfo, puArgErr);
2407 case DISPID_INSTALLER_PRODUCTS:
2408 return InstallerImpl_Products(wFlags, pDispParams,
2409 pVarResult, pExcepInfo, puArgErr);
2411 case DISPID_INSTALLER_RELATEDPRODUCTS:
2412 return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2413 pVarResult, pExcepInfo,
2414 puArgErr);
2416 default:
2417 return DISP_E_MEMBERNOTFOUND;
2421 HRESULT create_msiserver(IUnknown *outer, void **ppObj)
2423 AutomationObject *installer;
2425 TRACE("(%p %p)\n", outer, ppObj);
2427 if (outer)
2428 return CLASS_E_NOAGGREGATION;
2430 installer = msi_alloc(sizeof(AutomationObject));
2431 if (!installer) return E_OUTOFMEMORY;
2433 init_automation_object(installer, 0, Installer_tid);
2435 *ppObj = &installer->IDispatch_iface;
2437 return S_OK;
2440 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp)
2442 SessionObject *session;
2444 session = msi_alloc(sizeof(SessionObject));
2445 if (!session) return E_OUTOFMEMORY;
2447 init_automation_object(&session->autoobj, msiHandle, Session_tid);
2449 session->installer = installer;
2450 *disp = &session->autoobj.IDispatch_iface;
2452 return S_OK;
2455 static HRESULT create_database(MSIHANDLE msiHandle, IDispatch **dispatch)
2457 AutomationObject *database;
2459 TRACE("%lu %p\n", msiHandle, dispatch);
2461 database = msi_alloc(sizeof(AutomationObject));
2462 if (!database) return E_OUTOFMEMORY;
2464 init_automation_object(database, msiHandle, Database_tid);
2466 *dispatch = &database->IDispatch_iface;
2468 return S_OK;
2471 static HRESULT create_view(MSIHANDLE msiHandle, IDispatch **dispatch)
2473 AutomationObject *view;
2475 TRACE("%lu %p\n", msiHandle, dispatch);
2477 view = msi_alloc(sizeof(AutomationObject));
2478 if (!view) return E_OUTOFMEMORY;
2480 init_automation_object(view, msiHandle, View_tid);
2482 *dispatch = &view->IDispatch_iface;
2484 return S_OK;
2487 static HRESULT create_summaryinfo(MSIHANDLE msiHandle, IDispatch **disp)
2489 AutomationObject *info;
2491 info = msi_alloc(sizeof(*info));
2492 if (!info) return E_OUTOFMEMORY;
2494 init_automation_object(info, msiHandle, SummaryInfo_tid);
2496 *disp = &info->IDispatch_iface;
2498 return S_OK;