msvcp90: Add implementation of _Concurrent_vector_Internal_push_back.
[wine.git] / dlls / msi / automation.c
blob06ad2f90a4b2466d9cc2ad65b78b83f6f4ada299
1 /*
2 * Implementation of OLE Automation for Microsoft Installer (msi.dll)
4 * Copyright 2007 Misha Koshelev
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "msidefs.h"
30 #include "msipriv.h"
31 #include "activscp.h"
32 #include "oleauto.h"
33 #include "shlwapi.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 #include "msiserver.h"
38 #include "msiserver_dispids.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42 #define REG_INDEX_CLASSES_ROOT 0
43 #define REG_INDEX_DYN_DATA 6
45 typedef struct AutomationObject AutomationObject;
47 /* function that is called from AutomationObject::Invoke, specific to this type of object */
48 typedef HRESULT (*auto_invoke_func)(AutomationObject* This,
49 DISPID dispIdMember, REFIID riid, LCID lcid, WORD flags, DISPPARAMS* pDispParams,
50 VARIANT* result, EXCEPINFO* ei, UINT* arg_err);
51 /* function that is called from AutomationObject::Release when the object is being freed
52 to free any private data structures (or NULL) */
53 typedef void (*auto_free_func)(AutomationObject* This);
55 typedef struct {
56 REFIID riid;
57 auto_invoke_func fn_invoke;
58 auto_free_func fn_free;
59 } tid_id_t;
62 static HRESULT database_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
63 static HRESULT installer_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
64 static HRESULT record_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
65 static HRESULT session_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
66 static HRESULT list_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
67 static void list_free(AutomationObject*);
68 static HRESULT summaryinfo_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
69 static HRESULT view_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
71 static tid_id_t tid_ids[] = {
72 { &DIID_Database, database_invoke },
73 { &DIID_Installer, installer_invoke },
74 { &DIID_Record, record_invoke },
75 { &DIID_Session, session_invoke },
76 { &DIID_StringList, list_invoke, list_free },
77 { &DIID_SummaryInfo, summaryinfo_invoke },
78 { &DIID_View, view_invoke }
81 static ITypeLib *typelib;
82 static ITypeInfo *typeinfos[LAST_tid];
84 static const IID *get_riid_from_tid(tid_t tid)
86 return tid_ids[tid].riid;
89 HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo)
91 HRESULT hr;
93 if (!typelib)
95 ITypeLib *lib;
97 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, LOCALE_NEUTRAL, &lib);
98 if (FAILED(hr)) {
99 static const WCHAR msiserverW[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b',0};
100 hr = LoadTypeLib(msiserverW, &lib);
101 if (FAILED(hr)) {
102 ERR("Could not load msiserver.tlb\n");
103 return hr;
107 if (InterlockedCompareExchangePointer((void**)&typelib, lib, NULL))
108 ITypeLib_Release(lib);
111 if (!typeinfos[tid])
113 ITypeInfo *ti;
115 hr = ITypeLib_GetTypeInfoOfGuid(typelib, get_riid_from_tid(tid), &ti);
116 if (FAILED(hr)) {
117 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(get_riid_from_tid(tid)));
118 return hr;
121 if(InterlockedCompareExchangePointer((void**)(typeinfos+tid), ti, NULL))
122 ITypeInfo_Release(ti);
125 *typeinfo = typeinfos[tid];
126 return S_OK;
129 void release_typelib(void)
131 unsigned i;
133 for (i = 0; i < sizeof(typeinfos)/sizeof(*typeinfos); i++)
134 if (typeinfos[i])
135 ITypeInfo_Release(typeinfos[i]);
137 if (typelib)
138 ITypeLib_Release(typelib);
142 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
143 * called from AutomationObject::Invoke.
145 struct AutomationObject {
146 IDispatch IDispatch_iface;
147 IProvideMultipleClassInfo IProvideMultipleClassInfo_iface;
148 LONG ref;
150 /* type id for this class */
151 tid_t tid;
153 /* The MSI handle of the current object */
154 MSIHANDLE msiHandle;
157 typedef struct {
158 AutomationObject autoobj;
159 int count;
160 VARIANT *data;
161 } ListObject;
163 static HRESULT create_database(MSIHANDLE, IDispatch**);
164 static HRESULT create_list_enumerator(ListObject*, void**);
165 static HRESULT create_summaryinfo(MSIHANDLE, IDispatch**);
166 static HRESULT create_view(MSIHANDLE, IDispatch**);
168 /* ListEnumerator - IEnumVARIANT implementation for MSI automation lists */
169 typedef struct {
170 IEnumVARIANT IEnumVARIANT_iface;
171 LONG ref;
173 /* Current position and pointer to AutomationObject that stores actual data */
174 ULONG pos;
175 ListObject *list;
176 } ListEnumerator;
178 typedef struct {
179 AutomationObject autoobj;
180 IDispatch *installer;
181 } SessionObject;
183 static inline AutomationObject *impl_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
185 return CONTAINING_RECORD(iface, AutomationObject, IProvideMultipleClassInfo_iface);
188 static inline AutomationObject *impl_from_IDispatch( IDispatch *iface )
190 return CONTAINING_RECORD(iface, AutomationObject, IDispatch_iface);
193 /* AutomationObject methods */
194 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
196 AutomationObject *This = impl_from_IDispatch(iface);
198 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
200 if (ppvObject == NULL)
201 return E_INVALIDARG;
203 *ppvObject = 0;
205 if (IsEqualGUID(riid, &IID_IUnknown) ||
206 IsEqualGUID(riid, &IID_IDispatch) ||
207 IsEqualGUID(riid, get_riid_from_tid(This->tid)))
208 *ppvObject = &This->IDispatch_iface;
209 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
210 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
211 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
212 *ppvObject = &This->IProvideMultipleClassInfo_iface;
213 else
215 TRACE("() : asking for unsupported interface %s\n", debugstr_guid(riid));
216 return E_NOINTERFACE;
219 IDispatch_AddRef(iface);
221 return S_OK;
224 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
226 AutomationObject *This = impl_from_IDispatch(iface);
228 TRACE("(%p/%p)\n", iface, This);
230 return InterlockedIncrement(&This->ref);
233 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
235 AutomationObject *This = impl_from_IDispatch(iface);
236 ULONG ref = InterlockedDecrement(&This->ref);
238 TRACE("(%p/%p)\n", iface, This);
240 if (!ref)
242 if (tid_ids[This->tid].fn_free) tid_ids[This->tid].fn_free(This);
243 MsiCloseHandle(This->msiHandle);
244 msi_free(This);
247 return ref;
250 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
251 IDispatch* iface,
252 UINT* pctinfo)
254 AutomationObject *This = impl_from_IDispatch(iface);
256 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
257 *pctinfo = 1;
258 return S_OK;
261 static HRESULT WINAPI AutomationObject_GetTypeInfo(
262 IDispatch* iface,
263 UINT iTInfo,
264 LCID lcid,
265 ITypeInfo** ppTInfo)
267 AutomationObject *This = impl_from_IDispatch(iface);
268 HRESULT hr;
270 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
272 hr = get_typeinfo(This->tid, ppTInfo);
273 if (FAILED(hr))
274 return hr;
276 ITypeInfo_AddRef(*ppTInfo);
277 return hr;
280 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
281 IDispatch* iface,
282 REFIID riid,
283 LPOLESTR* rgszNames,
284 UINT cNames,
285 LCID lcid,
286 DISPID* rgDispId)
288 AutomationObject *This = impl_from_IDispatch(iface);
289 ITypeInfo *ti;
290 HRESULT hr;
292 TRACE("(%p/%p)->(%s, %p, %d, %d, %p)\n", iface, This,
293 debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
295 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
297 hr = get_typeinfo(This->tid, &ti);
298 if (FAILED(hr))
299 return hr;
301 hr = ITypeInfo_GetIDsOfNames(ti, rgszNames, cNames, rgDispId);
302 if (hr == DISP_E_UNKNOWNNAME)
304 UINT idx;
305 for (idx=0; idx<cNames; idx++)
307 if (rgDispId[idx] == DISPID_UNKNOWN)
308 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(get_riid_from_tid(This->tid)));
311 return hr;
314 /* Maximum number of allowed function parameters+1 */
315 #define MAX_FUNC_PARAMS 20
317 /* Some error checking is done here to simplify individual object function invocation */
318 static HRESULT WINAPI AutomationObject_Invoke(
319 IDispatch* iface,
320 DISPID dispIdMember,
321 REFIID riid,
322 LCID lcid,
323 WORD wFlags,
324 DISPPARAMS* pDispParams,
325 VARIANT* pVarResult,
326 EXCEPINFO* pExcepInfo,
327 UINT* puArgErr)
329 AutomationObject *This = impl_from_IDispatch(iface);
330 HRESULT hr;
331 unsigned int uArgErr;
332 VARIANT varResultDummy;
333 BSTR bstrName = NULL;
334 ITypeInfo *ti;
336 TRACE("(%p/%p)->(%d, %s, %d, %d, %p, %p, %p, %p)\n", iface, This,
337 dispIdMember, debugstr_guid(riid), lcid, wFlags,
338 pDispParams, pVarResult, pExcepInfo, puArgErr);
340 if (!IsEqualIID(riid, &IID_NULL))
342 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
343 return DISP_E_UNKNOWNNAME;
346 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
348 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
349 return DISP_E_PARAMNOTOPTIONAL;
352 /* This simplifies our individual object invocation functions */
353 if (puArgErr == NULL) puArgErr = &uArgErr;
354 if (pVarResult == NULL) pVarResult = &varResultDummy;
356 hr = get_typeinfo(This->tid, &ti);
357 if (FAILED(hr))
358 return hr;
360 /* Assume return type is void unless determined otherwise */
361 VariantInit(pVarResult);
363 /* If we are tracing, we want to see the name of the member we are invoking */
364 if (TRACE_ON(msi))
366 ITypeInfo_GetDocumentation(ti, dispIdMember, &bstrName, NULL, NULL, NULL);
367 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
370 hr = tid_ids[This->tid].fn_invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
372 if (hr == DISP_E_MEMBERNOTFOUND) {
373 if (bstrName == NULL) ITypeInfo_GetDocumentation(ti, dispIdMember, &bstrName, NULL, NULL, NULL);
374 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags,
375 debugstr_guid(get_riid_from_tid(This->tid)));
377 else if (pExcepInfo &&
378 (hr == DISP_E_PARAMNOTFOUND ||
379 hr == DISP_E_EXCEPTION)) {
380 static const WCHAR szComma[] = { ',',0 };
381 static const WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
382 WCHAR szExceptionDescription[MAX_PATH];
383 BSTR bstrParamNames[MAX_FUNC_PARAMS];
384 unsigned namesNo, i;
385 BOOL bFirst = TRUE;
387 if (FAILED(ITypeInfo_GetNames(ti, dispIdMember, bstrParamNames,
388 MAX_FUNC_PARAMS, &namesNo)))
390 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
392 else
394 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
395 for (i=0; i<namesNo; i++)
397 if (bFirst) bFirst = FALSE;
398 else {
399 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
401 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
402 SysFreeString(bstrParamNames[i]);
405 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
406 pExcepInfo->wCode = 1000;
407 pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
408 pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
409 hr = DISP_E_EXCEPTION;
413 /* Make sure we free the return variant if it is our dummy variant */
414 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
416 /* Free function name if we retrieved it */
417 SysFreeString(bstrName);
419 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
421 return hr;
424 static const struct IDispatchVtbl AutomationObjectVtbl =
426 AutomationObject_QueryInterface,
427 AutomationObject_AddRef,
428 AutomationObject_Release,
429 AutomationObject_GetTypeInfoCount,
430 AutomationObject_GetTypeInfo,
431 AutomationObject_GetIDsOfNames,
432 AutomationObject_Invoke
436 * IProvideMultipleClassInfo methods
439 static HRESULT WINAPI ProvideMultipleClassInfo_QueryInterface(
440 IProvideMultipleClassInfo* iface,
441 REFIID riid,
442 VOID** ppvoid)
444 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
445 return IDispatch_QueryInterface(&This->IDispatch_iface, riid, ppvoid);
448 static ULONG WINAPI ProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
450 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
451 return IDispatch_AddRef(&This->IDispatch_iface);
454 static ULONG WINAPI ProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
456 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
457 return IDispatch_Release(&This->IDispatch_iface);
460 static HRESULT WINAPI ProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
462 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
463 HRESULT hr;
465 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
467 hr = get_typeinfo(This->tid, ppTI);
468 if (SUCCEEDED(hr))
469 ITypeInfo_AddRef(*ppTI);
471 return hr;
474 static HRESULT WINAPI ProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
476 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
477 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
479 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
480 return E_INVALIDARG;
481 else {
482 *pGUID = *get_riid_from_tid(This->tid);
483 return S_OK;
487 static HRESULT WINAPI ProvideMultipleClassInfo_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
489 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
491 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
492 *pcti = 1;
493 return S_OK;
496 static HRESULT WINAPI ProvideMultipleClassInfo_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
497 ULONG iti,
498 DWORD dwFlags,
499 ITypeInfo** ti,
500 DWORD* pdwTIFlags,
501 ULONG* pcdispidReserved,
502 IID* piidPrimary,
503 IID* piidSource)
505 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
507 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, ti, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
509 if (iti != 0)
510 return E_INVALIDARG;
512 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
514 HRESULT hr = get_typeinfo(This->tid, ti);
515 if (FAILED(hr))
516 return hr;
518 ITypeInfo_AddRef(*ti);
521 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
523 *pdwTIFlags = 0;
524 *pcdispidReserved = 0;
527 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY)
528 *piidPrimary = *get_riid_from_tid(This->tid);
530 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE)
531 *piidSource = *get_riid_from_tid(This->tid);
533 return S_OK;
536 static const IProvideMultipleClassInfoVtbl ProvideMultipleClassInfoVtbl =
538 ProvideMultipleClassInfo_QueryInterface,
539 ProvideMultipleClassInfo_AddRef,
540 ProvideMultipleClassInfo_Release,
541 ProvideMultipleClassInfo_GetClassInfo,
542 ProvideMultipleClassInfo_GetGUID,
543 ProvideMultipleClassInfo_GetMultiTypeInfoCount,
544 ProvideMultipleClassInfo_GetInfoOfIndex
547 static HRESULT init_automation_object(AutomationObject *This, MSIHANDLE msiHandle, tid_t tid)
549 TRACE("(%p, %d, %s)\n", This, msiHandle, debugstr_guid(get_riid_from_tid(tid)));
551 This->IDispatch_iface.lpVtbl = &AutomationObjectVtbl;
552 This->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl;
553 This->ref = 1;
555 This->msiHandle = msiHandle;
556 This->tid = tid;
558 return S_OK;
562 * ListEnumerator methods
565 static inline ListEnumerator *impl_from_IEnumVARIANT(IEnumVARIANT* iface)
567 return CONTAINING_RECORD(iface, ListEnumerator, IEnumVARIANT_iface);
570 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid,
571 void** ppvObject)
573 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
575 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
577 if (ppvObject == NULL)
578 return E_INVALIDARG;
580 *ppvObject = 0;
582 if (IsEqualGUID(riid, &IID_IUnknown) ||
583 IsEqualGUID(riid, &IID_IEnumVARIANT))
585 *ppvObject = &This->IEnumVARIANT_iface;
587 else
589 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
590 return E_NOINTERFACE;
593 IEnumVARIANT_AddRef(iface);
594 return S_OK;
597 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
599 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
601 TRACE("(%p/%p)\n", iface, This);
603 return InterlockedIncrement(&This->ref);
606 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
608 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
609 ULONG ref = InterlockedDecrement(&This->ref);
611 TRACE("(%p/%p)\n", iface, This);
613 if (!ref)
615 if (This->list) IDispatch_Release(&This->list->autoobj.IDispatch_iface);
616 msi_free(This);
619 return ref;
622 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar,
623 ULONG* fetched)
625 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
626 ULONG i, local;
628 TRACE("(%p, %uld, %p, %p)\n", iface, celt, rgVar, fetched);
630 if (fetched) *fetched = 0;
632 if (!rgVar)
633 return S_FALSE;
635 for (local = 0; local < celt; local++)
636 VariantInit(&rgVar[local]);
638 for (i = This->pos, local = 0; i < This->list->count && local < celt; i++, local++)
639 VariantCopy(&rgVar[local], &This->list->data[i]);
641 if (fetched) *fetched = local;
642 This->pos = i;
644 return (local < celt) ? S_FALSE : S_OK;
647 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
649 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
651 TRACE("(%p,%uld)\n", iface, celt);
653 This->pos += celt;
654 if (This->pos >= This->list->count)
656 This->pos = This->list->count;
657 return S_FALSE;
660 return S_OK;
663 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
665 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
667 TRACE("(%p)\n", iface);
669 This->pos = 0;
670 return S_OK;
673 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
675 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
676 HRESULT hr;
678 TRACE("(%p,%p)\n", iface, ppEnum);
680 if (ppEnum == NULL)
681 return S_FALSE;
683 *ppEnum = NULL;
684 hr = create_list_enumerator(This->list, (LPVOID *)ppEnum);
685 if (FAILED(hr))
687 if (*ppEnum) IEnumVARIANT_Release(*ppEnum);
688 return hr;
691 return S_OK;
694 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
696 ListEnumerator_QueryInterface,
697 ListEnumerator_AddRef,
698 ListEnumerator_Release,
699 ListEnumerator_Next,
700 ListEnumerator_Skip,
701 ListEnumerator_Reset,
702 ListEnumerator_Clone
705 /* Create a list enumerator, placing the result in the pointer ppObj. */
706 static HRESULT create_list_enumerator(ListObject *list, void **ppObj)
708 ListEnumerator *object;
710 TRACE("(%p, %p)\n", list, ppObj);
712 object = msi_alloc(sizeof(ListEnumerator));
714 /* Set all the VTable references */
715 object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
716 object->ref = 1;
718 /* Store data that was passed */
719 object->pos = 0;
720 object->list = list;
721 if (list) IDispatch_AddRef(&list->autoobj.IDispatch_iface);
723 *ppObj = object;
724 return S_OK;
728 * Individual Object Invocation Functions
731 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
732 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
733 using DispGetParam/VariantChangeType. */
734 static HRESULT DispGetParam_CopyOnly(
735 DISPPARAMS *pdispparams, /* [in] Parameter list */
736 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
737 VARIANT *pvarResult) /* [out] Destination for resulting variant */
739 /* position is counted backwards */
740 UINT pos;
742 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
743 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
744 if (*position < pdispparams->cArgs) {
745 /* positional arg? */
746 pos = pdispparams->cArgs - *position - 1;
747 } else {
748 /* FIXME: is this how to handle named args? */
749 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
750 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
752 if (pos==pdispparams->cNamedArgs)
753 return DISP_E_PARAMNOTFOUND;
755 *position = pos;
756 return VariantCopyInd(pvarResult,
757 &pdispparams->rgvarg[pos]);
760 static HRESULT summaryinfo_invoke(
761 AutomationObject* This,
762 DISPID dispIdMember,
763 REFIID riid,
764 LCID lcid,
765 WORD wFlags,
766 DISPPARAMS* pDispParams,
767 VARIANT* pVarResult,
768 EXCEPINFO* pExcepInfo,
769 UINT* puArgErr)
771 UINT ret;
772 VARIANTARG varg0, varg1;
773 FILETIME ft, ftlocal;
774 SYSTEMTIME st;
775 HRESULT hr;
777 VariantInit(&varg0);
778 VariantInit(&varg1);
780 switch (dispIdMember)
782 case DISPID_SUMMARYINFO_PROPERTY:
783 if (wFlags & DISPATCH_PROPERTYGET)
785 UINT type;
786 INT value;
787 DWORD size = 0;
788 DATE date;
789 LPWSTR str;
791 static WCHAR szEmpty[] = {0};
793 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
794 if (FAILED(hr)) return hr;
795 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
796 &ft, szEmpty, &size);
797 if (ret != ERROR_SUCCESS &&
798 ret != ERROR_MORE_DATA)
800 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
801 return DISP_E_EXCEPTION;
804 switch (type)
806 case VT_EMPTY:
807 break;
809 case VT_I2:
810 case VT_I4:
811 V_VT(pVarResult) = VT_I4;
812 V_I4(pVarResult) = value;
813 break;
815 case VT_LPSTR:
816 if (!(str = msi_alloc(++size * sizeof(WCHAR))))
817 ERR("Out of memory\n");
818 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
819 NULL, str, &size)) != ERROR_SUCCESS)
820 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
821 else
823 V_VT(pVarResult) = VT_BSTR;
824 V_BSTR(pVarResult) = SysAllocString(str);
826 msi_free(str);
827 break;
829 case VT_FILETIME:
830 FileTimeToLocalFileTime(&ft, &ftlocal);
831 FileTimeToSystemTime(&ftlocal, &st);
832 SystemTimeToVariantTime(&st, &date);
834 V_VT(pVarResult) = VT_DATE;
835 V_DATE(pVarResult) = date;
836 break;
838 default:
839 ERR("Unhandled variant type %d\n", type);
842 else if (wFlags & DISPATCH_PROPERTYPUT)
844 UINT posValue = DISPID_PROPERTYPUT;
846 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
847 if (FAILED(hr)) return hr;
848 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
849 if (FAILED(hr))
851 *puArgErr = posValue;
852 return hr;
855 switch (V_VT(&varg1))
857 case VT_I2:
858 case VT_I4:
859 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
860 break;
862 case VT_DATE:
863 VariantTimeToSystemTime(V_DATE(&varg1), &st);
864 SystemTimeToFileTime(&st, &ftlocal);
865 LocalFileTimeToFileTime(&ftlocal, &ft);
866 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
867 break;
869 case VT_BSTR:
870 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
871 break;
873 default:
874 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
875 VariantClear(&varg1);
876 return DISP_E_EXCEPTION;
879 if (ret != ERROR_SUCCESS)
881 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
882 return DISP_E_EXCEPTION;
885 else return DISP_E_MEMBERNOTFOUND;
886 break;
888 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
889 if (wFlags & DISPATCH_PROPERTYGET) {
890 UINT count;
891 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
892 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
893 else
895 V_VT(pVarResult) = VT_I4;
896 V_I4(pVarResult) = count;
899 else return DISP_E_MEMBERNOTFOUND;
900 break;
902 default:
903 return DISP_E_MEMBERNOTFOUND;
906 VariantClear(&varg1);
907 VariantClear(&varg0);
909 return S_OK;
912 static HRESULT record_invoke(
913 AutomationObject* This,
914 DISPID dispIdMember,
915 REFIID riid,
916 LCID lcid,
917 WORD wFlags,
918 DISPPARAMS* pDispParams,
919 VARIANT* pVarResult,
920 EXCEPINFO* pExcepInfo,
921 UINT* puArgErr)
923 WCHAR *szString;
924 DWORD dwLen = 0;
925 UINT ret;
926 VARIANTARG varg0, varg1;
927 HRESULT hr;
929 VariantInit(&varg0);
930 VariantInit(&varg1);
932 switch (dispIdMember)
934 case DISPID_RECORD_FIELDCOUNT:
935 if (wFlags & DISPATCH_PROPERTYGET) {
936 V_VT(pVarResult) = VT_I4;
937 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
939 else return DISP_E_MEMBERNOTFOUND;
940 break;
942 case DISPID_RECORD_STRINGDATA:
943 if (wFlags & DISPATCH_PROPERTYGET) {
944 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
945 if (FAILED(hr)) return hr;
946 V_VT(pVarResult) = VT_BSTR;
947 V_BSTR(pVarResult) = NULL;
948 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
950 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
951 ERR("Out of memory\n");
952 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
953 V_BSTR(pVarResult) = SysAllocString(szString);
954 msi_free(szString);
956 if (ret != ERROR_SUCCESS)
957 ERR("MsiRecordGetString returned %d\n", ret);
958 } else if (wFlags & DISPATCH_PROPERTYPUT) {
959 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
960 if (FAILED(hr)) return hr;
961 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
962 if (FAILED(hr)) return hr;
963 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
965 VariantClear(&varg1);
966 ERR("MsiRecordSetString returned %d\n", ret);
967 return DISP_E_EXCEPTION;
970 else return DISP_E_MEMBERNOTFOUND;
971 break;
973 case DISPID_RECORD_INTEGERDATA:
974 if (wFlags & DISPATCH_PROPERTYGET) {
975 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
976 if (FAILED(hr)) return hr;
977 V_VT(pVarResult) = VT_I4;
978 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
979 } else if (wFlags & DISPATCH_PROPERTYPUT) {
980 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
981 if (FAILED(hr)) return hr;
982 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
983 if (FAILED(hr)) return hr;
984 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
986 ERR("MsiRecordSetInteger returned %d\n", ret);
987 return DISP_E_EXCEPTION;
990 else return DISP_E_MEMBERNOTFOUND;
991 break;
993 default:
994 return DISP_E_MEMBERNOTFOUND;
997 VariantClear(&varg1);
998 VariantClear(&varg0);
1000 return S_OK;
1003 static HRESULT create_record(MSIHANDLE msiHandle, IDispatch **disp)
1005 AutomationObject *record;
1006 HRESULT hr;
1008 record = msi_alloc(sizeof(*record));
1009 if (!record) return E_OUTOFMEMORY;
1011 hr = init_automation_object(record, msiHandle, Record_tid);
1012 if (hr != S_OK)
1014 msi_free(record);
1015 return hr;
1018 *disp = &record->IDispatch_iface;
1020 return hr;
1023 static HRESULT list_invoke(
1024 AutomationObject* This,
1025 DISPID dispIdMember,
1026 REFIID riid,
1027 LCID lcid,
1028 WORD wFlags,
1029 DISPPARAMS* pDispParams,
1030 VARIANT* pVarResult,
1031 EXCEPINFO* pExcepInfo,
1032 UINT* puArgErr)
1034 ListObject *list = CONTAINING_RECORD(This, ListObject, autoobj);
1035 IUnknown *pUnk = NULL;
1036 HRESULT hr;
1038 switch (dispIdMember)
1040 case DISPID_LIST__NEWENUM:
1041 if (wFlags & DISPATCH_METHOD) {
1042 V_VT(pVarResult) = VT_UNKNOWN;
1043 if (SUCCEEDED(hr = create_list_enumerator(list, (LPVOID *)&pUnk)))
1044 V_UNKNOWN(pVarResult) = pUnk;
1045 else
1046 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
1048 else return DISP_E_MEMBERNOTFOUND;
1049 break;
1051 case DISPID_LIST_ITEM:
1052 if (wFlags & DISPATCH_PROPERTYGET) {
1053 VARIANTARG index;
1055 VariantInit(&index);
1056 hr = DispGetParam(pDispParams, 0, VT_I4, &index, puArgErr);
1057 if (FAILED(hr)) return hr;
1058 if (V_I4(&index) < 0 || V_I4(&index) >= list->count)
1059 return DISP_E_BADINDEX;
1060 VariantCopy(pVarResult, &list->data[V_I4(&index)]);
1062 else return DISP_E_MEMBERNOTFOUND;
1063 break;
1065 case DISPID_LIST_COUNT:
1066 if (wFlags & DISPATCH_PROPERTYGET) {
1067 V_VT(pVarResult) = VT_I4;
1068 V_I4(pVarResult) = list->count;
1070 else return DISP_E_MEMBERNOTFOUND;
1071 break;
1073 default:
1074 return DISP_E_MEMBERNOTFOUND;
1077 return S_OK;
1080 static void list_free(AutomationObject *This)
1082 ListObject *list = CONTAINING_RECORD(This, ListObject, autoobj);
1083 int i;
1085 for (i = 0; i < list->count; i++)
1086 VariantClear(&list->data[i]);
1087 msi_free(list->data);
1090 static HRESULT get_products_count(const WCHAR *product, int *len)
1092 int i = 0;
1094 while (1)
1096 WCHAR dataW[GUID_SIZE];
1097 UINT ret;
1099 /* all or related only */
1100 if (product)
1101 ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1102 else
1103 ret = MsiEnumProductsW(i, dataW);
1105 if (ret == ERROR_NO_MORE_ITEMS) break;
1107 if (ret != ERROR_SUCCESS)
1108 return DISP_E_EXCEPTION;
1110 i++;
1113 *len = i;
1115 return S_OK;
1118 static HRESULT create_list(const WCHAR *product, IDispatch **dispatch)
1120 ListObject *list;
1121 HRESULT hr;
1122 int i;
1124 list = msi_alloc_zero(sizeof(ListObject));
1125 if (!list) return E_OUTOFMEMORY;
1127 hr = init_automation_object(&list->autoobj, 0, StringList_tid);
1128 if (hr != S_OK)
1130 msi_free(list);
1131 return hr;
1134 *dispatch = &list->autoobj.IDispatch_iface;
1136 hr = get_products_count(product, &list->count);
1137 if (hr != S_OK)
1139 IDispatch_Release(*dispatch);
1140 return hr;
1143 list->data = msi_alloc(list->count*sizeof(VARIANT));
1144 if (!list->data)
1146 IDispatch_Release(*dispatch);
1147 return E_OUTOFMEMORY;
1150 for (i = 0; i < list->count; i++)
1152 WCHAR dataW[GUID_SIZE];
1153 UINT ret;
1155 /* all or related only */
1156 if (product)
1157 ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1158 else
1159 ret = MsiEnumProductsW(i, dataW);
1161 if (ret == ERROR_NO_MORE_ITEMS) break;
1163 V_VT(&list->data[i]) = VT_BSTR;
1164 V_BSTR(&list->data[i]) = SysAllocString(dataW);
1167 return S_OK;
1170 static HRESULT view_invoke(
1171 AutomationObject* This,
1172 DISPID dispIdMember,
1173 REFIID riid,
1174 LCID lcid,
1175 WORD wFlags,
1176 DISPPARAMS* pDispParams,
1177 VARIANT* pVarResult,
1178 EXCEPINFO* pExcepInfo,
1179 UINT* puArgErr)
1181 MSIHANDLE msiHandle;
1182 UINT ret;
1183 VARIANTARG varg0, varg1;
1184 HRESULT hr;
1186 VariantInit(&varg0);
1187 VariantInit(&varg1);
1189 switch (dispIdMember)
1191 case DISPID_VIEW_EXECUTE:
1192 if (wFlags & DISPATCH_METHOD)
1194 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1195 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1196 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1197 else
1198 MsiViewExecute(This->msiHandle, 0);
1200 else return DISP_E_MEMBERNOTFOUND;
1201 break;
1203 case DISPID_VIEW_FETCH:
1204 if (wFlags & DISPATCH_METHOD)
1206 V_VT(pVarResult) = VT_DISPATCH;
1207 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1209 if (FAILED(hr = create_record(msiHandle, &V_DISPATCH(pVarResult))))
1210 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1212 else if (ret == ERROR_NO_MORE_ITEMS)
1213 V_DISPATCH(pVarResult) = NULL;
1214 else
1216 ERR("MsiViewFetch returned %d\n", ret);
1217 return DISP_E_EXCEPTION;
1220 else return DISP_E_MEMBERNOTFOUND;
1221 break;
1223 case DISPID_VIEW_MODIFY:
1224 if (wFlags & DISPATCH_METHOD)
1226 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1227 if (FAILED(hr)) return hr;
1228 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1229 if (FAILED(hr)) return hr;
1230 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1231 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1233 VariantClear(&varg1);
1234 ERR("MsiViewModify returned %d\n", ret);
1235 return DISP_E_EXCEPTION;
1238 else return DISP_E_MEMBERNOTFOUND;
1239 break;
1241 case DISPID_VIEW_CLOSE:
1242 if (wFlags & DISPATCH_METHOD)
1244 MsiViewClose(This->msiHandle);
1246 else return DISP_E_MEMBERNOTFOUND;
1247 break;
1249 default:
1250 return DISP_E_MEMBERNOTFOUND;
1253 VariantClear(&varg1);
1254 VariantClear(&varg0);
1256 return S_OK;
1259 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
1260 DISPPARAMS* pDispParams,
1261 VARIANT* pVarResult,
1262 EXCEPINFO* pExcepInfo,
1263 UINT* puArgErr)
1265 if (!(wFlags & DISPATCH_METHOD))
1266 return DISP_E_MEMBERNOTFOUND;
1268 FIXME("\n");
1270 VariantInit(pVarResult);
1271 return S_OK;
1274 HRESULT database_invoke(
1275 AutomationObject* This,
1276 DISPID dispIdMember,
1277 REFIID riid,
1278 LCID lcid,
1279 WORD wFlags,
1280 DISPPARAMS* pDispParams,
1281 VARIANT* pVarResult,
1282 EXCEPINFO* pExcepInfo,
1283 UINT* puArgErr)
1285 IDispatch *dispatch = NULL;
1286 MSIHANDLE msiHandle;
1287 UINT ret;
1288 VARIANTARG varg0, varg1;
1289 HRESULT hr;
1291 VariantInit(&varg0);
1292 VariantInit(&varg1);
1294 switch (dispIdMember)
1296 case DISPID_DATABASE_SUMMARYINFORMATION:
1297 if (wFlags & DISPATCH_PROPERTYGET)
1299 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1300 if (FAILED(hr))
1301 V_I4(&varg0) = 0;
1303 V_VT(pVarResult) = VT_DISPATCH;
1304 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1306 hr = create_summaryinfo(msiHandle, &dispatch);
1307 if (SUCCEEDED(hr))
1308 V_DISPATCH(pVarResult) = dispatch;
1309 else
1310 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1312 else
1314 ERR("MsiGetSummaryInformation returned %d\n", ret);
1315 return DISP_E_EXCEPTION;
1318 else return DISP_E_MEMBERNOTFOUND;
1319 break;
1321 case DISPID_DATABASE_OPENVIEW:
1322 if (wFlags & DISPATCH_METHOD)
1324 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1325 if (FAILED(hr)) return hr;
1326 V_VT(pVarResult) = VT_DISPATCH;
1327 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1329 if (SUCCEEDED(hr = create_view(msiHandle, &dispatch)))
1330 V_DISPATCH(pVarResult) = dispatch;
1331 else
1332 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1334 else
1336 VariantClear(&varg0);
1337 ERR("MsiDatabaseOpenView returned %d\n", ret);
1338 return DISP_E_EXCEPTION;
1341 else return DISP_E_MEMBERNOTFOUND;
1342 break;
1344 case DISPID_INSTALLER_LASTERRORRECORD:
1345 return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
1346 pVarResult, pExcepInfo,
1347 puArgErr);
1349 default:
1350 return DISP_E_MEMBERNOTFOUND;
1353 VariantClear(&varg1);
1354 VariantClear(&varg0);
1356 return S_OK;
1359 static HRESULT session_invoke(
1360 AutomationObject* This,
1361 DISPID dispIdMember,
1362 REFIID riid,
1363 LCID lcid,
1364 WORD wFlags,
1365 DISPPARAMS* pDispParams,
1366 VARIANT* pVarResult,
1367 EXCEPINFO* pExcepInfo,
1368 UINT* puArgErr)
1370 SessionObject *session = CONTAINING_RECORD(This, SessionObject, autoobj);
1371 WCHAR *szString;
1372 DWORD dwLen = 0;
1373 MSIHANDLE msiHandle;
1374 LANGID langId;
1375 UINT ret;
1376 INSTALLSTATE iInstalled, iAction;
1377 VARIANTARG varg0, varg1;
1378 HRESULT hr;
1380 VariantInit(&varg0);
1381 VariantInit(&varg1);
1383 switch (dispIdMember)
1385 case DISPID_SESSION_INSTALLER:
1386 if (wFlags & DISPATCH_PROPERTYGET) {
1387 V_VT(pVarResult) = VT_DISPATCH;
1388 IDispatch_AddRef(session->installer);
1389 V_DISPATCH(pVarResult) = session->installer;
1391 else return DISP_E_MEMBERNOTFOUND;
1392 break;
1394 case DISPID_SESSION_PROPERTY:
1395 if (wFlags & DISPATCH_PROPERTYGET) {
1396 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1397 if (FAILED(hr)) return hr;
1398 V_VT(pVarResult) = VT_BSTR;
1399 V_BSTR(pVarResult) = NULL;
1400 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1402 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1403 ERR("Out of memory\n");
1404 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1405 V_BSTR(pVarResult) = SysAllocString(szString);
1406 msi_free(szString);
1408 if (ret != ERROR_SUCCESS)
1409 ERR("MsiGetProperty returned %d\n", ret);
1410 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1411 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1412 if (FAILED(hr)) return hr;
1413 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1414 if (FAILED(hr)) {
1415 VariantClear(&varg0);
1416 return hr;
1418 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1420 VariantClear(&varg0);
1421 VariantClear(&varg1);
1422 ERR("MsiSetProperty returned %d\n", ret);
1423 return DISP_E_EXCEPTION;
1426 else return DISP_E_MEMBERNOTFOUND;
1427 break;
1429 case DISPID_SESSION_LANGUAGE:
1430 if (wFlags & DISPATCH_PROPERTYGET) {
1431 langId = MsiGetLanguage(This->msiHandle);
1432 V_VT(pVarResult) = VT_I4;
1433 V_I4(pVarResult) = langId;
1435 else return DISP_E_MEMBERNOTFOUND;
1436 break;
1438 case DISPID_SESSION_MODE:
1439 if (wFlags & DISPATCH_PROPERTYGET) {
1440 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1441 if (FAILED(hr)) return hr;
1442 V_VT(pVarResult) = VT_BOOL;
1443 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0)) ? VARIANT_TRUE : VARIANT_FALSE;
1444 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1445 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1446 if (FAILED(hr)) return hr;
1447 hr = DispGetParam(pDispParams, 1, VT_BOOL, &varg1, puArgErr);
1448 if (FAILED(hr)) return hr;
1449 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1451 ERR("MsiSetMode returned %d\n", ret);
1452 return DISP_E_EXCEPTION;
1455 else return DISP_E_MEMBERNOTFOUND;
1456 break;
1458 case DISPID_SESSION_DATABASE:
1459 if (wFlags & DISPATCH_PROPERTYGET) {
1460 V_VT(pVarResult) = VT_DISPATCH;
1461 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1463 IDispatch *dispatch;
1465 if (SUCCEEDED(hr = create_database(msiHandle, &dispatch)))
1466 V_DISPATCH(pVarResult) = dispatch;
1467 else
1468 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1470 else
1472 ERR("MsiGetActiveDatabase failed\n");
1473 return DISP_E_EXCEPTION;
1476 else return DISP_E_MEMBERNOTFOUND;
1477 break;
1479 case DISPID_SESSION_DOACTION:
1480 if (wFlags & DISPATCH_METHOD) {
1481 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1482 if (FAILED(hr)) return hr;
1483 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1484 V_VT(pVarResult) = VT_I4;
1485 switch (ret)
1487 case ERROR_FUNCTION_NOT_CALLED:
1488 V_I4(pVarResult) = msiDoActionStatusNoAction;
1489 break;
1490 case ERROR_SUCCESS:
1491 V_I4(pVarResult) = msiDoActionStatusSuccess;
1492 break;
1493 case ERROR_INSTALL_USEREXIT:
1494 V_I4(pVarResult) = msiDoActionStatusUserExit;
1495 break;
1496 case ERROR_INSTALL_FAILURE:
1497 V_I4(pVarResult) = msiDoActionStatusFailure;
1498 break;
1499 case ERROR_INSTALL_SUSPEND:
1500 V_I4(pVarResult) = msiDoActionStatusSuspend;
1501 break;
1502 case ERROR_MORE_DATA:
1503 V_I4(pVarResult) = msiDoActionStatusFinished;
1504 break;
1505 case ERROR_INVALID_HANDLE_STATE:
1506 V_I4(pVarResult) = msiDoActionStatusWrongState;
1507 break;
1508 case ERROR_INVALID_DATA:
1509 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1510 break;
1511 default:
1512 VariantClear(&varg0);
1513 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1514 return DISP_E_EXCEPTION;
1517 else return DISP_E_MEMBERNOTFOUND;
1518 break;
1520 case DISPID_SESSION_EVALUATECONDITION:
1521 if (wFlags & DISPATCH_METHOD) {
1522 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1523 if (FAILED(hr)) return hr;
1524 V_VT(pVarResult) = VT_I4;
1525 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1527 else return DISP_E_MEMBERNOTFOUND;
1528 break;
1530 case DISPID_SESSION_MESSAGE:
1531 if(!(wFlags & DISPATCH_METHOD))
1532 return DISP_E_MEMBERNOTFOUND;
1534 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1535 if (FAILED(hr)) return hr;
1536 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1537 if (FAILED(hr)) return hr;
1539 V_VT(pVarResult) = VT_I4;
1540 V_I4(pVarResult) =
1541 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
1542 break;
1544 case DISPID_SESSION_SETINSTALLLEVEL:
1545 if (wFlags & DISPATCH_METHOD) {
1546 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1547 if (FAILED(hr)) return hr;
1548 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1550 ERR("MsiSetInstallLevel returned %d\n", ret);
1551 return DISP_E_EXCEPTION;
1554 else return DISP_E_MEMBERNOTFOUND;
1555 break;
1557 case DISPID_SESSION_FEATURECURRENTSTATE:
1558 if (wFlags & DISPATCH_PROPERTYGET) {
1559 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1560 if (FAILED(hr)) return hr;
1561 V_VT(pVarResult) = VT_I4;
1562 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1563 V_I4(pVarResult) = iInstalled;
1564 else
1566 ERR("MsiGetFeatureState returned %d\n", ret);
1567 V_I4(pVarResult) = msiInstallStateUnknown;
1570 else return DISP_E_MEMBERNOTFOUND;
1571 break;
1573 case DISPID_SESSION_FEATUREREQUESTSTATE:
1574 if (wFlags & DISPATCH_PROPERTYGET) {
1575 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1576 if (FAILED(hr)) return hr;
1577 V_VT(pVarResult) = VT_I4;
1578 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1579 V_I4(pVarResult) = iAction;
1580 else
1582 ERR("MsiGetFeatureState returned %d\n", ret);
1583 V_I4(pVarResult) = msiInstallStateUnknown;
1585 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1586 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1587 if (FAILED(hr)) return hr;
1588 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1589 if (FAILED(hr)) {
1590 VariantClear(&varg0);
1591 return hr;
1593 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1595 VariantClear(&varg0);
1596 ERR("MsiSetFeatureState returned %d\n", ret);
1597 return DISP_E_EXCEPTION;
1600 else return DISP_E_MEMBERNOTFOUND;
1601 break;
1603 default:
1604 return DISP_E_MEMBERNOTFOUND;
1607 VariantClear(&varg1);
1608 VariantClear(&varg0);
1610 return S_OK;
1613 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1614 * registry value type. Used by Installer::RegistryValue. */
1615 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1617 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1618 static const WCHAR szREG_[] = { '(','R','E','G','_','?','?',')',0 };
1619 WCHAR *szString = (WCHAR *)lpData;
1620 LPWSTR szNewString = NULL;
1621 DWORD dwNewSize = 0;
1622 int idx;
1624 switch (dwType)
1626 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1627 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1628 idx = (dwSize/sizeof(WCHAR))-1;
1629 while (idx >= 0 && !szString[idx]) idx--;
1630 for (; idx >= 0; idx--)
1631 if (!szString[idx]) szString[idx] = '\n';
1632 /* fall through */
1633 case REG_SZ:
1634 V_VT(pVarResult) = VT_BSTR;
1635 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1636 break;
1638 case REG_EXPAND_SZ:
1639 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1640 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1641 else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1642 ERR("Out of memory\n");
1643 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1644 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1645 else
1647 V_VT(pVarResult) = VT_BSTR;
1648 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1650 msi_free(szNewString);
1651 break;
1653 case REG_DWORD:
1654 V_VT(pVarResult) = VT_I4;
1655 V_I4(pVarResult) = *((DWORD *)lpData);
1656 break;
1658 case REG_QWORD:
1659 V_VT(pVarResult) = VT_BSTR;
1660 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1661 break;
1663 case REG_BINARY:
1664 V_VT(pVarResult) = VT_BSTR;
1665 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1666 break;
1668 case REG_NONE:
1669 V_VT(pVarResult) = VT_EMPTY;
1670 break;
1672 default:
1673 FIXME("Unhandled registry value type %d\n", dwType);
1677 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1678 DISPPARAMS* pDispParams,
1679 VARIANT* pVarResult,
1680 EXCEPINFO* pExcepInfo,
1681 UINT* puArgErr)
1683 HRESULT hr;
1684 VARIANTARG varg0;
1685 MSIHANDLE hrec;
1687 if (!(wFlags & DISPATCH_METHOD))
1688 return DISP_E_MEMBERNOTFOUND;
1690 VariantInit(&varg0);
1691 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1692 if (FAILED(hr))
1693 return hr;
1695 V_VT(pVarResult) = VT_DISPATCH;
1697 hrec = MsiCreateRecord(V_I4(&varg0));
1698 if (!hrec)
1699 return DISP_E_EXCEPTION;
1701 return create_record(hrec, &V_DISPATCH(pVarResult));
1704 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1705 WORD wFlags,
1706 DISPPARAMS* pDispParams,
1707 VARIANT* pVarResult,
1708 EXCEPINFO* pExcepInfo,
1709 UINT* puArgErr)
1711 UINT ret;
1712 HRESULT hr;
1713 MSIHANDLE hpkg;
1714 IDispatch* dispatch;
1715 VARIANTARG varg0, varg1;
1717 if (!(wFlags & DISPATCH_METHOD))
1718 return DISP_E_MEMBERNOTFOUND;
1720 if (pDispParams->cArgs == 0)
1721 return DISP_E_TYPEMISMATCH;
1723 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1724 return DISP_E_TYPEMISMATCH;
1726 VariantInit(&varg0);
1727 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1728 if (FAILED(hr))
1729 return hr;
1731 VariantInit(&varg1);
1732 if (pDispParams->cArgs == 2)
1734 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1735 if (FAILED(hr))
1736 goto done;
1738 else
1740 V_VT(&varg1) = VT_I4;
1741 V_I4(&varg1) = 0;
1744 V_VT(pVarResult) = VT_DISPATCH;
1746 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1747 if (ret != ERROR_SUCCESS)
1749 hr = DISP_E_EXCEPTION;
1750 goto done;
1753 hr = create_session(hpkg, &This->IDispatch_iface, &dispatch);
1754 if (SUCCEEDED(hr))
1755 V_DISPATCH(pVarResult) = dispatch;
1757 done:
1758 VariantClear(&varg0);
1759 VariantClear(&varg1);
1760 return hr;
1763 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1764 DISPPARAMS* pDispParams,
1765 VARIANT* pVarResult,
1766 EXCEPINFO* pExcepInfo,
1767 UINT* puArgErr)
1769 HRESULT hr;
1770 VARIANTARG varg0;
1772 if (!(wFlags & DISPATCH_METHOD))
1773 return DISP_E_MEMBERNOTFOUND;
1775 VariantInit(&varg0);
1776 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1777 if (FAILED(hr))
1778 return hr;
1780 FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1782 VariantInit(pVarResult);
1784 VariantClear(&varg0);
1785 return S_OK;
1788 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1789 DISPPARAMS* pDispParams,
1790 VARIANT* pVarResult,
1791 EXCEPINFO* pExcepInfo,
1792 UINT* puArgErr)
1794 UINT ret;
1795 HRESULT hr;
1796 MSIHANDLE hdb;
1797 IDispatch* dispatch;
1798 VARIANTARG varg0, varg1;
1800 if (!(wFlags & DISPATCH_METHOD))
1801 return DISP_E_MEMBERNOTFOUND;
1803 VariantInit(&varg0);
1804 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1805 if (FAILED(hr))
1806 return hr;
1808 VariantInit(&varg1);
1809 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1810 if (FAILED(hr))
1811 goto done;
1813 V_VT(pVarResult) = VT_DISPATCH;
1815 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1816 if (ret != ERROR_SUCCESS)
1818 hr = DISP_E_EXCEPTION;
1819 goto done;
1822 hr = create_database(hdb, &dispatch);
1823 if (SUCCEEDED(hr))
1824 V_DISPATCH(pVarResult) = dispatch;
1826 done:
1827 VariantClear(&varg0);
1828 VariantClear(&varg1);
1829 return hr;
1832 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1833 DISPPARAMS* pDispParams,
1834 VARIANT* pVarResult,
1835 EXCEPINFO* pExcepInfo,
1836 UINT* puArgErr)
1838 UINT ret;
1839 HRESULT hr;
1840 MSIHANDLE hsuminfo;
1841 IDispatch *dispatch;
1842 VARIANTARG varg0, varg1;
1844 if (!(wFlags & DISPATCH_PROPERTYGET))
1845 return DISP_E_MEMBERNOTFOUND;
1847 VariantInit(&varg1);
1848 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1849 if (FAILED(hr))
1850 return hr;
1852 VariantInit(&varg0);
1853 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1854 if (FAILED(hr))
1855 return hr;
1857 ret = MsiGetSummaryInformationW(0, V_BSTR(&varg0), V_I4(&varg1), &hsuminfo);
1858 VariantClear(&varg0);
1859 if (ret != ERROR_SUCCESS)
1860 return DISP_E_EXCEPTION;
1862 hr = create_summaryinfo(hsuminfo, &dispatch);
1863 if (FAILED(hr))
1864 return hr;
1866 V_VT(pVarResult) = VT_DISPATCH;
1867 V_DISPATCH(pVarResult) = dispatch;
1868 return S_OK;
1871 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1872 DISPPARAMS* pDispParams,
1873 VARIANT* pVarResult,
1874 EXCEPINFO* pExcepInfo,
1875 UINT* puArgErr)
1877 HRESULT hr;
1878 VARIANTARG varg0;
1879 INSTALLUILEVEL ui;
1881 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1882 return DISP_E_MEMBERNOTFOUND;
1884 if (wFlags & DISPATCH_PROPERTYPUT)
1886 VariantInit(&varg0);
1887 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1888 if (FAILED(hr))
1889 return hr;
1891 ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1892 if (ui == INSTALLUILEVEL_NOCHANGE)
1893 return DISP_E_EXCEPTION;
1895 else if (wFlags & DISPATCH_PROPERTYGET)
1897 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1898 if (ui == INSTALLUILEVEL_NOCHANGE)
1899 return DISP_E_EXCEPTION;
1901 V_VT(pVarResult) = VT_I4;
1902 V_I4(pVarResult) = ui;
1905 return S_OK;
1908 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1909 DISPPARAMS* pDispParams,
1910 VARIANT* pVarResult,
1911 EXCEPINFO* pExcepInfo,
1912 UINT* puArgErr)
1914 if (!(wFlags & DISPATCH_METHOD))
1915 return DISP_E_MEMBERNOTFOUND;
1917 FIXME("\n");
1919 VariantInit(pVarResult);
1920 return S_OK;
1923 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1924 DISPPARAMS* pDispParams,
1925 VARIANT* pVarResult,
1926 EXCEPINFO* pExcepInfo,
1927 UINT* puArgErr)
1929 UINT ret;
1930 HRESULT hr;
1931 VARIANTARG varg0, varg1;
1933 if (!(wFlags & DISPATCH_METHOD))
1934 return DISP_E_MEMBERNOTFOUND;
1936 VariantInit(&varg0);
1937 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1938 if (FAILED(hr))
1939 return hr;
1941 VariantInit(&varg1);
1942 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1943 if (FAILED(hr))
1944 goto done;
1946 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1947 if (ret != ERROR_SUCCESS)
1949 hr = DISP_E_EXCEPTION;
1950 goto done;
1953 done:
1954 VariantClear(&varg0);
1955 VariantClear(&varg1);
1956 return hr;
1959 static HRESULT InstallerImpl_Version(WORD wFlags,
1960 VARIANT* pVarResult,
1961 EXCEPINFO* pExcepInfo,
1962 UINT* puArgErr)
1964 HRESULT hr;
1965 DLLVERSIONINFO verinfo;
1966 WCHAR version[MAX_PATH];
1968 static const WCHAR format[] = {
1969 '%','d','.','%','d','.','%','d','.','%','d',0};
1971 if (!(wFlags & DISPATCH_PROPERTYGET))
1972 return DISP_E_MEMBERNOTFOUND;
1974 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1975 hr = DllGetVersion(&verinfo);
1976 if (FAILED(hr))
1977 return hr;
1979 sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1980 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1982 V_VT(pVarResult) = VT_BSTR;
1983 V_BSTR(pVarResult) = SysAllocString(version);
1984 return S_OK;
1987 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1988 DISPPARAMS* pDispParams,
1989 VARIANT* pVarResult,
1990 EXCEPINFO* pExcepInfo,
1991 UINT* puArgErr)
1993 if (!(wFlags & DISPATCH_METHOD))
1994 return DISP_E_MEMBERNOTFOUND;
1996 FIXME("\n");
1998 VariantInit(pVarResult);
1999 return S_OK;
2002 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
2003 DISPPARAMS* pDispParams,
2004 VARIANT* pVarResult,
2005 EXCEPINFO* pExcepInfo,
2006 UINT* puArgErr)
2008 UINT ret;
2009 HKEY hkey = NULL;
2010 HRESULT hr;
2011 UINT posValue;
2012 DWORD type, size;
2013 LPWSTR szString = NULL;
2014 VARIANTARG varg0, varg1, varg2;
2016 if (!(wFlags & DISPATCH_METHOD))
2017 return DISP_E_MEMBERNOTFOUND;
2019 VariantInit(&varg0);
2020 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
2021 if (FAILED(hr))
2022 return hr;
2024 VariantInit(&varg1);
2025 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2026 if (FAILED(hr))
2027 goto done;
2029 /* Save valuePos so we can save puArgErr if we are unable to do our type
2030 * conversions.
2032 posValue = 2;
2033 VariantInit(&varg2);
2034 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
2035 if (FAILED(hr))
2036 goto done;
2038 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
2039 V_I4(&varg0) <= REG_INDEX_DYN_DATA)
2041 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
2044 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
2046 /* Only VT_EMPTY case can do anything if the key doesn't exist. */
2047 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
2049 hr = DISP_E_BADINDEX;
2050 goto done;
2053 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
2054 switch (V_VT(&varg2))
2056 /* Return VT_BOOL clarifying whether registry key exists or not. */
2057 case VT_EMPTY:
2058 V_VT(pVarResult) = VT_BOOL;
2059 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS) ? VARIANT_TRUE : VARIANT_FALSE;
2060 break;
2062 /* Return the value of specified key if it exists. */
2063 case VT_BSTR:
2064 ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
2065 NULL, NULL, NULL, &size);
2066 if (ret != ERROR_SUCCESS)
2068 hr = DISP_E_BADINDEX;
2069 goto done;
2072 szString = msi_alloc(size);
2073 if (!szString)
2075 hr = E_OUTOFMEMORY;
2076 goto done;
2079 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
2080 &type, (LPBYTE)szString, &size);
2081 if (ret != ERROR_SUCCESS)
2083 msi_free(szString);
2084 hr = DISP_E_BADINDEX;
2085 goto done;
2088 variant_from_registry_value(pVarResult, type,
2089 (LPBYTE)szString, size);
2090 msi_free(szString);
2091 break;
2093 /* Try to make it into VT_I4, can use VariantChangeType for this. */
2094 default:
2095 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
2096 if (FAILED(hr))
2098 if (hr == DISP_E_TYPEMISMATCH)
2099 *puArgErr = posValue;
2101 goto done;
2104 /* Retrieve class name or maximum value name or subkey name size. */
2105 if (!V_I4(&varg2))
2106 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
2107 NULL, NULL, NULL, NULL, NULL, NULL);
2108 else if (V_I4(&varg2) > 0)
2109 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
2110 NULL, NULL, &size, NULL, NULL, NULL);
2111 else /* V_I4(&varg2) < 0 */
2112 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
2113 NULL, NULL, NULL, NULL, NULL, NULL);
2115 if (ret != ERROR_SUCCESS)
2116 goto done;
2118 szString = msi_alloc(++size * sizeof(WCHAR));
2119 if (!szString)
2121 hr = E_OUTOFMEMORY;
2122 goto done;
2125 if (!V_I4(&varg2))
2126 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
2127 NULL, NULL, NULL, NULL, NULL, NULL);
2128 else if (V_I4(&varg2) > 0)
2129 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
2130 &size, 0, 0, NULL, NULL);
2131 else /* V_I4(&varg2) < 0 */
2132 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
2134 if (ret == ERROR_SUCCESS)
2136 V_VT(pVarResult) = VT_BSTR;
2137 V_BSTR(pVarResult) = SysAllocString(szString);
2140 msi_free(szString);
2143 done:
2144 VariantClear(&varg0);
2145 VariantClear(&varg1);
2146 VariantClear(&varg2);
2147 RegCloseKey(hkey);
2148 return hr;
2151 static HRESULT InstallerImpl_Environment(WORD wFlags,
2152 DISPPARAMS* pDispParams,
2153 VARIANT* pVarResult,
2154 EXCEPINFO* pExcepInfo,
2155 UINT* puArgErr)
2157 if (!(wFlags & DISPATCH_METHOD))
2158 return DISP_E_MEMBERNOTFOUND;
2160 FIXME("\n");
2162 VariantInit(pVarResult);
2163 return S_OK;
2166 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2167 DISPPARAMS* pDispParams,
2168 VARIANT* pVarResult,
2169 EXCEPINFO* pExcepInfo,
2170 UINT* puArgErr)
2172 if (!(wFlags & DISPATCH_METHOD))
2173 return DISP_E_MEMBERNOTFOUND;
2175 FIXME("\n");
2177 VariantInit(pVarResult);
2178 return S_OK;
2181 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2182 DISPPARAMS* pDispParams,
2183 VARIANT* pVarResult,
2184 EXCEPINFO* pExcepInfo,
2185 UINT* puArgErr)
2187 if (!(wFlags & DISPATCH_METHOD))
2188 return DISP_E_MEMBERNOTFOUND;
2190 FIXME("\n");
2192 VariantInit(pVarResult);
2193 return S_OK;
2196 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2197 DISPPARAMS* pDispParams,
2198 VARIANT* pVarResult,
2199 EXCEPINFO* pExcepInfo,
2200 UINT* puArgErr)
2202 if (!(wFlags & DISPATCH_METHOD))
2203 return DISP_E_MEMBERNOTFOUND;
2205 FIXME("\n");
2207 VariantInit(pVarResult);
2208 return S_OK;
2211 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2212 DISPPARAMS* pDispParams,
2213 VARIANT* pVarResult,
2214 EXCEPINFO* pExcepInfo,
2215 UINT* puArgErr)
2217 HRESULT hr;
2218 VARIANTARG varg0;
2220 if (!(wFlags & DISPATCH_PROPERTYGET))
2221 return DISP_E_MEMBERNOTFOUND;
2223 VariantInit(&varg0);
2224 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2225 if (FAILED(hr))
2226 return hr;
2228 V_VT(pVarResult) = VT_I4;
2229 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2231 VariantClear(&varg0);
2232 return S_OK;
2235 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2236 DISPPARAMS* pDispParams,
2237 VARIANT* pVarResult,
2238 EXCEPINFO* pExcepInfo,
2239 UINT* puArgErr)
2241 UINT ret;
2242 HRESULT hr;
2243 DWORD size;
2244 LPWSTR str = NULL;
2245 VARIANTARG varg0, varg1;
2247 if (!(wFlags & DISPATCH_PROPERTYGET))
2248 return DISP_E_MEMBERNOTFOUND;
2250 VariantInit(&varg0);
2251 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2252 if (FAILED(hr))
2253 return hr;
2255 VariantInit(&varg1);
2256 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2257 if (FAILED(hr))
2258 goto done;
2260 V_VT(pVarResult) = VT_BSTR;
2261 V_BSTR(pVarResult) = NULL;
2263 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2264 if (ret != ERROR_SUCCESS)
2266 hr = DISP_E_EXCEPTION;
2267 goto done;
2270 str = msi_alloc(++size * sizeof(WCHAR));
2271 if (!str)
2273 hr = E_OUTOFMEMORY;
2274 goto done;
2277 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2278 if (ret != ERROR_SUCCESS)
2280 hr = DISP_E_EXCEPTION;
2281 goto done;
2284 V_BSTR(pVarResult) = SysAllocString(str);
2285 hr = S_OK;
2287 done:
2288 msi_free(str);
2289 VariantClear(&varg0);
2290 VariantClear(&varg1);
2291 return hr;
2294 static HRESULT InstallerImpl_Products(WORD flags,
2295 DISPPARAMS* pDispParams,
2296 VARIANT* result,
2297 EXCEPINFO* pExcepInfo,
2298 UINT* puArgErr)
2300 IDispatch *dispatch;
2301 HRESULT hr;
2303 if (!(flags & DISPATCH_PROPERTYGET))
2304 return DISP_E_MEMBERNOTFOUND;
2306 hr = create_list(NULL, &dispatch);
2307 if (FAILED(hr))
2308 return hr;
2310 V_VT(result) = VT_DISPATCH;
2311 V_DISPATCH(result) = dispatch;
2313 return hr;
2316 static HRESULT InstallerImpl_RelatedProducts(WORD flags,
2317 DISPPARAMS* pDispParams,
2318 VARIANT* result,
2319 EXCEPINFO* pExcepInfo,
2320 UINT* puArgErr)
2322 IDispatch* dispatch;
2323 VARIANTARG related;
2324 HRESULT hr;
2326 if (!(flags & DISPATCH_PROPERTYGET))
2327 return DISP_E_MEMBERNOTFOUND;
2329 VariantInit(&related);
2330 hr = DispGetParam(pDispParams, 0, VT_BSTR, &related, puArgErr);
2331 if (FAILED(hr))
2332 return hr;
2334 hr = create_list(V_BSTR(&related), &dispatch);
2335 VariantClear(&related);
2337 V_VT(result) = VT_DISPATCH;
2338 V_DISPATCH(result) = dispatch;
2340 return hr;
2343 static HRESULT installer_invoke(
2344 AutomationObject* This,
2345 DISPID dispIdMember,
2346 REFIID riid,
2347 LCID lcid,
2348 WORD wFlags,
2349 DISPPARAMS* pDispParams,
2350 VARIANT* pVarResult,
2351 EXCEPINFO* pExcepInfo,
2352 UINT* puArgErr)
2354 switch (dispIdMember)
2356 case DISPID_INSTALLER_CREATERECORD:
2357 return InstallerImpl_CreateRecord(wFlags, pDispParams,
2358 pVarResult, pExcepInfo, puArgErr);
2360 case DISPID_INSTALLER_OPENPACKAGE:
2361 return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2362 pVarResult, pExcepInfo, puArgErr);
2364 case DISPID_INSTALLER_OPENPRODUCT:
2365 return InstallerImpl_OpenProduct(wFlags, pDispParams,
2366 pVarResult, pExcepInfo, puArgErr);
2368 case DISPID_INSTALLER_OPENDATABASE:
2369 return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2370 pVarResult, pExcepInfo, puArgErr);
2372 case DISPID_INSTALLER_SUMMARYINFORMATION:
2373 return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2374 pVarResult, pExcepInfo,
2375 puArgErr);
2377 case DISPID_INSTALLER_UILEVEL:
2378 return InstallerImpl_UILevel(wFlags, pDispParams,
2379 pVarResult, pExcepInfo, puArgErr);
2381 case DISPID_INSTALLER_ENABLELOG:
2382 return InstallerImpl_EnableLog(wFlags, pDispParams,
2383 pVarResult, pExcepInfo, puArgErr);
2385 case DISPID_INSTALLER_INSTALLPRODUCT:
2386 return InstallerImpl_InstallProduct(wFlags, pDispParams,
2387 pVarResult, pExcepInfo,
2388 puArgErr);
2390 case DISPID_INSTALLER_VERSION:
2391 return InstallerImpl_Version(wFlags, pVarResult,
2392 pExcepInfo, puArgErr);
2394 case DISPID_INSTALLER_LASTERRORRECORD:
2395 return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2396 pVarResult, pExcepInfo,
2397 puArgErr);
2399 case DISPID_INSTALLER_REGISTRYVALUE:
2400 return InstallerImpl_RegistryValue(wFlags, pDispParams,
2401 pVarResult, pExcepInfo,
2402 puArgErr);
2404 case DISPID_INSTALLER_ENVIRONMENT:
2405 return InstallerImpl_Environment(wFlags, pDispParams,
2406 pVarResult, pExcepInfo, puArgErr);
2408 case DISPID_INSTALLER_FILEATTRIBUTES:
2409 return InstallerImpl_FileAttributes(wFlags, pDispParams,
2410 pVarResult, pExcepInfo,
2411 puArgErr);
2413 case DISPID_INSTALLER_FILESIZE:
2414 return InstallerImpl_FileSize(wFlags, pDispParams,
2415 pVarResult, pExcepInfo, puArgErr);
2417 case DISPID_INSTALLER_FILEVERSION:
2418 return InstallerImpl_FileVersion(wFlags, pDispParams,
2419 pVarResult, pExcepInfo, puArgErr);
2421 case DISPID_INSTALLER_PRODUCTSTATE:
2422 return InstallerImpl_ProductState(wFlags, pDispParams,
2423 pVarResult, pExcepInfo, puArgErr);
2425 case DISPID_INSTALLER_PRODUCTINFO:
2426 return InstallerImpl_ProductInfo(wFlags, pDispParams,
2427 pVarResult, pExcepInfo, puArgErr);
2429 case DISPID_INSTALLER_PRODUCTS:
2430 return InstallerImpl_Products(wFlags, pDispParams,
2431 pVarResult, pExcepInfo, puArgErr);
2433 case DISPID_INSTALLER_RELATEDPRODUCTS:
2434 return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2435 pVarResult, pExcepInfo,
2436 puArgErr);
2438 default:
2439 return DISP_E_MEMBERNOTFOUND;
2443 HRESULT create_msiserver(IUnknown *outer, void **ppObj)
2445 AutomationObject *installer;
2446 HRESULT hr;
2448 TRACE("(%p %p)\n", outer, ppObj);
2450 if (outer)
2451 return CLASS_E_NOAGGREGATION;
2453 installer = msi_alloc(sizeof(AutomationObject));
2454 if (!installer) return E_OUTOFMEMORY;
2456 hr = init_automation_object(installer, 0, Installer_tid);
2457 if (hr != S_OK)
2459 msi_free(installer);
2460 return hr;
2463 *ppObj = &installer->IDispatch_iface;
2465 return hr;
2468 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp)
2470 SessionObject *session;
2471 HRESULT hr;
2473 session = msi_alloc(sizeof(SessionObject));
2474 if (!session) return E_OUTOFMEMORY;
2476 hr = init_automation_object(&session->autoobj, msiHandle, Session_tid);
2477 if (hr != S_OK)
2479 msi_free(session);
2480 return hr;
2483 session->installer = installer;
2484 *disp = &session->autoobj.IDispatch_iface;
2486 return hr;
2489 static HRESULT create_database(MSIHANDLE msiHandle, IDispatch **dispatch)
2491 AutomationObject *database;
2492 HRESULT hr;
2494 TRACE("(%d %p)\n", msiHandle, dispatch);
2496 database = msi_alloc(sizeof(AutomationObject));
2497 if (!database) return E_OUTOFMEMORY;
2499 hr = init_automation_object(database, msiHandle, Database_tid);
2500 if (hr != S_OK)
2502 msi_free(database);
2503 return hr;
2506 *dispatch = &database->IDispatch_iface;
2508 return hr;
2511 static HRESULT create_view(MSIHANDLE msiHandle, IDispatch **dispatch)
2513 AutomationObject *view;
2514 HRESULT hr;
2516 TRACE("(%d %p)\n", msiHandle, dispatch);
2518 view = msi_alloc(sizeof(AutomationObject));
2519 if (!view) return E_OUTOFMEMORY;
2521 hr = init_automation_object(view, msiHandle, View_tid);
2522 if (hr != S_OK)
2524 msi_free(view);
2525 return hr;
2528 *dispatch = &view->IDispatch_iface;
2530 return hr;
2533 static HRESULT create_summaryinfo(MSIHANDLE msiHandle, IDispatch **disp)
2535 AutomationObject *info;
2536 HRESULT hr;
2538 info = msi_alloc(sizeof(*info));
2539 if (!info) return E_OUTOFMEMORY;
2541 hr = init_automation_object(info, msiHandle, SummaryInfo_tid);
2542 if (hr != S_OK)
2544 msi_free(info);
2545 return hr;
2548 *disp = &info->IDispatch_iface;
2550 return hr;