TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / msi / automation.c
blobc3d2c677386a92cd42d1abdac8104fdf5b907e8e
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)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
294 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
296 hr = get_typeinfo(This->tid, &ti);
297 if (FAILED(hr))
298 return hr;
300 hr = ITypeInfo_GetIDsOfNames(ti, rgszNames, cNames, rgDispId);
301 if (hr == DISP_E_UNKNOWNNAME)
303 UINT idx;
304 for (idx=0; idx<cNames; idx++)
306 if (rgDispId[idx] == DISPID_UNKNOWN)
307 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(get_riid_from_tid(This->tid)));
310 return hr;
313 /* Maximum number of allowed function parameters+1 */
314 #define MAX_FUNC_PARAMS 20
316 /* Some error checking is done here to simplify individual object function invocation */
317 static HRESULT WINAPI AutomationObject_Invoke(
318 IDispatch* iface,
319 DISPID dispIdMember,
320 REFIID riid,
321 LCID lcid,
322 WORD wFlags,
323 DISPPARAMS* pDispParams,
324 VARIANT* pVarResult,
325 EXCEPINFO* pExcepInfo,
326 UINT* puArgErr)
328 AutomationObject *This = impl_from_IDispatch(iface);
329 HRESULT hr;
330 unsigned int uArgErr;
331 VARIANT varResultDummy;
332 BSTR bstrName = NULL;
333 ITypeInfo *ti;
335 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
337 if (!IsEqualIID(riid, &IID_NULL))
339 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
340 return DISP_E_UNKNOWNNAME;
343 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
345 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
346 return DISP_E_PARAMNOTOPTIONAL;
349 /* This simplifies our individual object invocation functions */
350 if (puArgErr == NULL) puArgErr = &uArgErr;
351 if (pVarResult == NULL) pVarResult = &varResultDummy;
353 hr = get_typeinfo(This->tid, &ti);
354 if (FAILED(hr))
355 return hr;
357 /* Assume return type is void unless determined otherwise */
358 VariantInit(pVarResult);
360 /* If we are tracing, we want to see the name of the member we are invoking */
361 if (TRACE_ON(msi))
363 ITypeInfo_GetDocumentation(ti, dispIdMember, &bstrName, NULL, NULL, NULL);
364 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
367 hr = tid_ids[This->tid].fn_invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
369 if (hr == DISP_E_MEMBERNOTFOUND) {
370 if (bstrName == NULL) ITypeInfo_GetDocumentation(ti, dispIdMember, &bstrName, NULL, NULL, NULL);
371 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags,
372 debugstr_guid(get_riid_from_tid(This->tid)));
374 else if (pExcepInfo &&
375 (hr == DISP_E_PARAMNOTFOUND ||
376 hr == DISP_E_EXCEPTION)) {
377 static const WCHAR szComma[] = { ',',0 };
378 static const WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
379 WCHAR szExceptionDescription[MAX_PATH];
380 BSTR bstrParamNames[MAX_FUNC_PARAMS];
381 unsigned namesNo, i;
382 BOOL bFirst = TRUE;
384 if (FAILED(ITypeInfo_GetNames(ti, dispIdMember, bstrParamNames,
385 MAX_FUNC_PARAMS, &namesNo)))
387 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
389 else
391 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
392 for (i=0; i<namesNo; i++)
394 if (bFirst) bFirst = FALSE;
395 else {
396 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
398 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
399 SysFreeString(bstrParamNames[i]);
402 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
403 pExcepInfo->wCode = 1000;
404 pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
405 pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
406 hr = DISP_E_EXCEPTION;
410 /* Make sure we free the return variant if it is our dummy variant */
411 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
413 /* Free function name if we retrieved it */
414 SysFreeString(bstrName);
416 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
418 return hr;
421 static const struct IDispatchVtbl AutomationObjectVtbl =
423 AutomationObject_QueryInterface,
424 AutomationObject_AddRef,
425 AutomationObject_Release,
426 AutomationObject_GetTypeInfoCount,
427 AutomationObject_GetTypeInfo,
428 AutomationObject_GetIDsOfNames,
429 AutomationObject_Invoke
433 * IProvideMultipleClassInfo methods
436 static HRESULT WINAPI ProvideMultipleClassInfo_QueryInterface(
437 IProvideMultipleClassInfo* iface,
438 REFIID riid,
439 VOID** ppvoid)
441 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
442 return IDispatch_QueryInterface(&This->IDispatch_iface, riid, ppvoid);
445 static ULONG WINAPI ProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
447 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
448 return IDispatch_AddRef(&This->IDispatch_iface);
451 static ULONG WINAPI ProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
453 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
454 return IDispatch_Release(&This->IDispatch_iface);
457 static HRESULT WINAPI ProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
459 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
460 HRESULT hr;
462 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
464 hr = get_typeinfo(This->tid, ppTI);
465 if (SUCCEEDED(hr))
466 ITypeInfo_AddRef(*ppTI);
468 return hr;
471 static HRESULT WINAPI ProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
473 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
474 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
476 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
477 return E_INVALIDARG;
478 else {
479 *pGUID = *get_riid_from_tid(This->tid);
480 return S_OK;
484 static HRESULT WINAPI ProvideMultipleClassInfo_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
486 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
488 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
489 *pcti = 1;
490 return S_OK;
493 static HRESULT WINAPI ProvideMultipleClassInfo_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
494 ULONG iti,
495 DWORD dwFlags,
496 ITypeInfo** ti,
497 DWORD* pdwTIFlags,
498 ULONG* pcdispidReserved,
499 IID* piidPrimary,
500 IID* piidSource)
502 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
504 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, ti, pdwTIFlags, pcdispidReserved, 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 HRESULT init_automation_object(AutomationObject *This, MSIHANDLE msiHandle, tid_t tid)
546 TRACE("(%p, %d, %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;
552 This->msiHandle = msiHandle;
553 This->tid = tid;
555 return S_OK;
559 * ListEnumerator methods
562 static inline ListEnumerator *impl_from_IEnumVARIANT(IEnumVARIANT* iface)
564 return CONTAINING_RECORD(iface, ListEnumerator, IEnumVARIANT_iface);
567 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid,
568 void** ppvObject)
570 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
572 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
574 if (ppvObject == NULL)
575 return E_INVALIDARG;
577 *ppvObject = 0;
579 if (IsEqualGUID(riid, &IID_IUnknown) ||
580 IsEqualGUID(riid, &IID_IEnumVARIANT))
582 *ppvObject = &This->IEnumVARIANT_iface;
584 else
586 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
587 return E_NOINTERFACE;
590 IEnumVARIANT_AddRef(iface);
591 return S_OK;
594 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
596 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
598 TRACE("(%p/%p)\n", iface, This);
600 return InterlockedIncrement(&This->ref);
603 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
605 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
606 ULONG ref = InterlockedDecrement(&This->ref);
608 TRACE("(%p/%p)\n", iface, This);
610 if (!ref)
612 if (This->list) IDispatch_Release(&This->list->autoobj.IDispatch_iface);
613 msi_free(This);
616 return ref;
619 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar,
620 ULONG* fetched)
622 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
623 ULONG i, local;
625 TRACE("(%p, %uld, %p, %p)\n", iface, celt, rgVar, fetched);
627 if (fetched) *fetched = 0;
629 if (!rgVar)
630 return S_FALSE;
632 for (local = 0; local < celt; local++)
633 VariantInit(&rgVar[local]);
635 for (i = This->pos, local = 0; i < This->list->count && local < celt; i++, local++)
636 VariantCopy(&rgVar[local], &This->list->data[i]);
638 if (fetched) *fetched = local;
639 This->pos = i;
641 return (local < celt) ? S_FALSE : S_OK;
644 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
646 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
648 TRACE("(%p,%uld)\n", iface, celt);
650 This->pos += celt;
651 if (This->pos >= This->list->count)
653 This->pos = This->list->count;
654 return S_FALSE;
657 return S_OK;
660 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
662 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
664 TRACE("(%p)\n", iface);
666 This->pos = 0;
667 return S_OK;
670 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
672 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
673 HRESULT hr;
675 TRACE("(%p,%p)\n", iface, ppEnum);
677 if (ppEnum == NULL)
678 return S_FALSE;
680 *ppEnum = NULL;
681 hr = create_list_enumerator(This->list, (LPVOID *)ppEnum);
682 if (FAILED(hr))
684 if (*ppEnum) IEnumVARIANT_Release(*ppEnum);
685 return hr;
688 return S_OK;
691 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
693 ListEnumerator_QueryInterface,
694 ListEnumerator_AddRef,
695 ListEnumerator_Release,
696 ListEnumerator_Next,
697 ListEnumerator_Skip,
698 ListEnumerator_Reset,
699 ListEnumerator_Clone
702 /* Create a list enumerator, placing the result in the pointer ppObj. */
703 static HRESULT create_list_enumerator(ListObject *list, void **ppObj)
705 ListEnumerator *object;
707 TRACE("(%p, %p)\n", list, ppObj);
709 object = msi_alloc(sizeof(ListEnumerator));
711 /* Set all the VTable references */
712 object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
713 object->ref = 1;
715 /* Store data that was passed */
716 object->pos = 0;
717 object->list = list;
718 if (list) IDispatch_AddRef(&list->autoobj.IDispatch_iface);
720 *ppObj = object;
721 return S_OK;
725 * Individual Object Invocation Functions
728 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
729 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
730 using DispGetParam/VariantChangeType. */
731 static HRESULT DispGetParam_CopyOnly(
732 DISPPARAMS *pdispparams, /* [in] Parameter list */
733 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
734 VARIANT *pvarResult) /* [out] Destination for resulting variant */
736 /* position is counted backwards */
737 UINT pos;
739 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
740 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
741 if (*position < pdispparams->cArgs) {
742 /* positional arg? */
743 pos = pdispparams->cArgs - *position - 1;
744 } else {
745 /* FIXME: is this how to handle named args? */
746 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
747 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
749 if (pos==pdispparams->cNamedArgs)
750 return DISP_E_PARAMNOTFOUND;
752 *position = pos;
753 return VariantCopyInd(pvarResult,
754 &pdispparams->rgvarg[pos]);
757 static HRESULT summaryinfo_invoke(
758 AutomationObject* This,
759 DISPID dispIdMember,
760 REFIID riid,
761 LCID lcid,
762 WORD wFlags,
763 DISPPARAMS* pDispParams,
764 VARIANT* pVarResult,
765 EXCEPINFO* pExcepInfo,
766 UINT* puArgErr)
768 UINT ret;
769 VARIANTARG varg0, varg1;
770 FILETIME ft, ftlocal;
771 SYSTEMTIME st;
772 HRESULT hr;
774 VariantInit(&varg0);
775 VariantInit(&varg1);
777 switch (dispIdMember)
779 case DISPID_SUMMARYINFO_PROPERTY:
780 if (wFlags & DISPATCH_PROPERTYGET)
782 UINT type;
783 INT value;
784 DWORD size = 0;
785 DATE date;
786 LPWSTR str;
788 static WCHAR szEmpty[] = {0};
790 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
791 if (FAILED(hr)) return hr;
792 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
793 &ft, szEmpty, &size);
794 if (ret != ERROR_SUCCESS &&
795 ret != ERROR_MORE_DATA)
797 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
798 return DISP_E_EXCEPTION;
801 switch (type)
803 case VT_EMPTY:
804 break;
806 case VT_I2:
807 case VT_I4:
808 V_VT(pVarResult) = VT_I4;
809 V_I4(pVarResult) = value;
810 break;
812 case VT_LPSTR:
813 if (!(str = msi_alloc(++size * sizeof(WCHAR))))
814 ERR("Out of memory\n");
815 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
816 NULL, str, &size)) != ERROR_SUCCESS)
817 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
818 else
820 V_VT(pVarResult) = VT_BSTR;
821 V_BSTR(pVarResult) = SysAllocString(str);
823 msi_free(str);
824 break;
826 case VT_FILETIME:
827 FileTimeToLocalFileTime(&ft, &ftlocal);
828 FileTimeToSystemTime(&ftlocal, &st);
829 SystemTimeToVariantTime(&st, &date);
831 V_VT(pVarResult) = VT_DATE;
832 V_DATE(pVarResult) = date;
833 break;
835 default:
836 ERR("Unhandled variant type %d\n", type);
839 else if (wFlags & DISPATCH_PROPERTYPUT)
841 UINT posValue = DISPID_PROPERTYPUT;
843 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
844 if (FAILED(hr)) return hr;
845 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
846 if (FAILED(hr))
848 *puArgErr = posValue;
849 return hr;
852 switch (V_VT(&varg1))
854 case VT_I2:
855 case VT_I4:
856 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
857 break;
859 case VT_DATE:
860 VariantTimeToSystemTime(V_DATE(&varg1), &st);
861 SystemTimeToFileTime(&st, &ftlocal);
862 LocalFileTimeToFileTime(&ftlocal, &ft);
863 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
864 break;
866 case VT_BSTR:
867 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
868 break;
870 default:
871 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
872 VariantClear(&varg1);
873 return DISP_E_EXCEPTION;
876 if (ret != ERROR_SUCCESS)
878 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
879 return DISP_E_EXCEPTION;
882 else return DISP_E_MEMBERNOTFOUND;
883 break;
885 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
886 if (wFlags & DISPATCH_PROPERTYGET) {
887 UINT count;
888 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
889 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
890 else
892 V_VT(pVarResult) = VT_I4;
893 V_I4(pVarResult) = count;
896 else return DISP_E_MEMBERNOTFOUND;
897 break;
899 default:
900 return DISP_E_MEMBERNOTFOUND;
903 VariantClear(&varg1);
904 VariantClear(&varg0);
906 return S_OK;
909 static HRESULT record_invoke(
910 AutomationObject* This,
911 DISPID dispIdMember,
912 REFIID riid,
913 LCID lcid,
914 WORD wFlags,
915 DISPPARAMS* pDispParams,
916 VARIANT* pVarResult,
917 EXCEPINFO* pExcepInfo,
918 UINT* puArgErr)
920 WCHAR *szString;
921 DWORD dwLen = 0;
922 UINT ret;
923 VARIANTARG varg0, varg1;
924 HRESULT hr;
926 VariantInit(&varg0);
927 VariantInit(&varg1);
929 switch (dispIdMember)
931 case DISPID_RECORD_FIELDCOUNT:
932 if (wFlags & DISPATCH_PROPERTYGET) {
933 V_VT(pVarResult) = VT_I4;
934 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
936 else return DISP_E_MEMBERNOTFOUND;
937 break;
939 case DISPID_RECORD_STRINGDATA:
940 if (wFlags & DISPATCH_PROPERTYGET) {
941 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
942 if (FAILED(hr)) return hr;
943 V_VT(pVarResult) = VT_BSTR;
944 V_BSTR(pVarResult) = NULL;
945 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
947 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
948 ERR("Out of memory\n");
949 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
950 V_BSTR(pVarResult) = SysAllocString(szString);
951 msi_free(szString);
953 if (ret != ERROR_SUCCESS)
954 ERR("MsiRecordGetString returned %d\n", ret);
955 } else if (wFlags & DISPATCH_PROPERTYPUT) {
956 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
957 if (FAILED(hr)) return hr;
958 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
959 if (FAILED(hr)) return hr;
960 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
962 VariantClear(&varg1);
963 ERR("MsiRecordSetString returned %d\n", ret);
964 return DISP_E_EXCEPTION;
967 else return DISP_E_MEMBERNOTFOUND;
968 break;
970 case DISPID_RECORD_INTEGERDATA:
971 if (wFlags & DISPATCH_PROPERTYGET) {
972 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
973 if (FAILED(hr)) return hr;
974 V_VT(pVarResult) = VT_I4;
975 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
976 } else if (wFlags & DISPATCH_PROPERTYPUT) {
977 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
978 if (FAILED(hr)) return hr;
979 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
980 if (FAILED(hr)) return hr;
981 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
983 ERR("MsiRecordSetInteger returned %d\n", ret);
984 return DISP_E_EXCEPTION;
987 else return DISP_E_MEMBERNOTFOUND;
988 break;
990 default:
991 return DISP_E_MEMBERNOTFOUND;
994 VariantClear(&varg1);
995 VariantClear(&varg0);
997 return S_OK;
1000 static HRESULT create_record(MSIHANDLE msiHandle, IDispatch **disp)
1002 AutomationObject *record;
1003 HRESULT hr;
1005 record = msi_alloc(sizeof(*record));
1006 if (!record) return E_OUTOFMEMORY;
1008 hr = init_automation_object(record, msiHandle, Record_tid);
1009 if (hr != S_OK)
1011 msi_free(record);
1012 return hr;
1015 *disp = &record->IDispatch_iface;
1017 return hr;
1020 static HRESULT list_invoke(
1021 AutomationObject* This,
1022 DISPID dispIdMember,
1023 REFIID riid,
1024 LCID lcid,
1025 WORD wFlags,
1026 DISPPARAMS* pDispParams,
1027 VARIANT* pVarResult,
1028 EXCEPINFO* pExcepInfo,
1029 UINT* puArgErr)
1031 ListObject *list = (ListObject*)This;
1032 IUnknown *pUnk = NULL;
1033 HRESULT hr;
1035 switch (dispIdMember)
1037 case DISPID_LIST__NEWENUM:
1038 if (wFlags & DISPATCH_METHOD) {
1039 V_VT(pVarResult) = VT_UNKNOWN;
1040 if (SUCCEEDED(hr = create_list_enumerator(list, (LPVOID *)&pUnk)))
1041 V_UNKNOWN(pVarResult) = pUnk;
1042 else
1043 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
1045 else return DISP_E_MEMBERNOTFOUND;
1046 break;
1048 case DISPID_LIST_ITEM:
1049 if (wFlags & DISPATCH_PROPERTYGET) {
1050 VARIANTARG index;
1052 VariantInit(&index);
1053 hr = DispGetParam(pDispParams, 0, VT_I4, &index, puArgErr);
1054 if (FAILED(hr)) return hr;
1055 if (V_I4(&index) < 0 || V_I4(&index) >= list->count)
1056 return DISP_E_BADINDEX;
1057 VariantCopy(pVarResult, &list->data[V_I4(&index)]);
1059 else return DISP_E_MEMBERNOTFOUND;
1060 break;
1062 case DISPID_LIST_COUNT:
1063 if (wFlags & DISPATCH_PROPERTYGET) {
1064 V_VT(pVarResult) = VT_I4;
1065 V_I4(pVarResult) = list->count;
1067 else return DISP_E_MEMBERNOTFOUND;
1068 break;
1070 default:
1071 return DISP_E_MEMBERNOTFOUND;
1074 return S_OK;
1077 static void list_free(AutomationObject *This)
1079 ListObject *list = (ListObject*)This;
1080 int i;
1082 for (i = 0; i < list->count; i++)
1083 VariantClear(&list->data[i]);
1084 msi_free(list->data);
1087 static HRESULT get_products_count(const WCHAR *product, int *len)
1089 int i = 0;
1091 while (1)
1093 WCHAR dataW[GUID_SIZE];
1094 UINT ret;
1096 /* all or related only */
1097 if (product)
1098 ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1099 else
1100 ret = MsiEnumProductsW(i, dataW);
1102 if (ret == ERROR_NO_MORE_ITEMS) break;
1104 if (ret != ERROR_SUCCESS)
1105 return DISP_E_EXCEPTION;
1107 i++;
1110 *len = i;
1112 return S_OK;
1115 static HRESULT create_list(const WCHAR *product, IDispatch **dispatch)
1117 ListObject *list;
1118 HRESULT hr;
1119 int i;
1121 list = msi_alloc_zero(sizeof(ListObject));
1122 if (!list) return E_OUTOFMEMORY;
1124 hr = init_automation_object(&list->autoobj, 0, StringList_tid);
1125 if (hr != S_OK)
1127 msi_free(list);
1128 return hr;
1131 *dispatch = &list->autoobj.IDispatch_iface;
1133 hr = get_products_count(product, &list->count);
1134 if (hr != S_OK)
1136 IDispatch_Release(*dispatch);
1137 return hr;
1140 list->data = msi_alloc(list->count*sizeof(VARIANT));
1141 if (!list->data)
1143 IDispatch_Release(*dispatch);
1144 return E_OUTOFMEMORY;
1147 for (i = 0; i < list->count; i++)
1149 WCHAR dataW[GUID_SIZE];
1150 UINT ret;
1152 /* all or related only */
1153 if (product)
1154 ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1155 else
1156 ret = MsiEnumProductsW(i, dataW);
1158 if (ret == ERROR_NO_MORE_ITEMS) break;
1160 V_VT(&list->data[i]) = VT_BSTR;
1161 V_BSTR(&list->data[i]) = SysAllocString(dataW);
1164 return S_OK;
1167 static HRESULT view_invoke(
1168 AutomationObject* This,
1169 DISPID dispIdMember,
1170 REFIID riid,
1171 LCID lcid,
1172 WORD wFlags,
1173 DISPPARAMS* pDispParams,
1174 VARIANT* pVarResult,
1175 EXCEPINFO* pExcepInfo,
1176 UINT* puArgErr)
1178 MSIHANDLE msiHandle;
1179 UINT ret;
1180 VARIANTARG varg0, varg1;
1181 HRESULT hr;
1183 VariantInit(&varg0);
1184 VariantInit(&varg1);
1186 switch (dispIdMember)
1188 case DISPID_VIEW_EXECUTE:
1189 if (wFlags & DISPATCH_METHOD)
1191 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1192 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1193 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1194 else
1195 MsiViewExecute(This->msiHandle, 0);
1197 else return DISP_E_MEMBERNOTFOUND;
1198 break;
1200 case DISPID_VIEW_FETCH:
1201 if (wFlags & DISPATCH_METHOD)
1203 V_VT(pVarResult) = VT_DISPATCH;
1204 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1206 if (FAILED(hr = create_record(msiHandle, &V_DISPATCH(pVarResult))))
1207 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1209 else if (ret == ERROR_NO_MORE_ITEMS)
1210 V_DISPATCH(pVarResult) = NULL;
1211 else
1213 ERR("MsiViewFetch returned %d\n", ret);
1214 return DISP_E_EXCEPTION;
1217 else return DISP_E_MEMBERNOTFOUND;
1218 break;
1220 case DISPID_VIEW_MODIFY:
1221 if (wFlags & DISPATCH_METHOD)
1223 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1224 if (FAILED(hr)) return hr;
1225 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1226 if (FAILED(hr)) return hr;
1227 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1228 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1230 VariantClear(&varg1);
1231 ERR("MsiViewModify returned %d\n", ret);
1232 return DISP_E_EXCEPTION;
1235 else return DISP_E_MEMBERNOTFOUND;
1236 break;
1238 case DISPID_VIEW_CLOSE:
1239 if (wFlags & DISPATCH_METHOD)
1241 MsiViewClose(This->msiHandle);
1243 else return DISP_E_MEMBERNOTFOUND;
1244 break;
1246 default:
1247 return DISP_E_MEMBERNOTFOUND;
1250 VariantClear(&varg1);
1251 VariantClear(&varg0);
1253 return S_OK;
1256 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
1257 DISPPARAMS* pDispParams,
1258 VARIANT* pVarResult,
1259 EXCEPINFO* pExcepInfo,
1260 UINT* puArgErr)
1262 if (!(wFlags & DISPATCH_METHOD))
1263 return DISP_E_MEMBERNOTFOUND;
1265 FIXME("\n");
1267 VariantInit(pVarResult);
1268 return S_OK;
1271 HRESULT database_invoke(
1272 AutomationObject* This,
1273 DISPID dispIdMember,
1274 REFIID riid,
1275 LCID lcid,
1276 WORD wFlags,
1277 DISPPARAMS* pDispParams,
1278 VARIANT* pVarResult,
1279 EXCEPINFO* pExcepInfo,
1280 UINT* puArgErr)
1282 IDispatch *dispatch = NULL;
1283 MSIHANDLE msiHandle;
1284 UINT ret;
1285 VARIANTARG varg0, varg1;
1286 HRESULT hr;
1288 VariantInit(&varg0);
1289 VariantInit(&varg1);
1291 switch (dispIdMember)
1293 case DISPID_DATABASE_SUMMARYINFORMATION:
1294 if (wFlags & DISPATCH_PROPERTYGET)
1296 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1297 if (FAILED(hr))
1298 V_I4(&varg0) = 0;
1300 V_VT(pVarResult) = VT_DISPATCH;
1301 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1303 hr = create_summaryinfo(msiHandle, &dispatch);
1304 if (SUCCEEDED(hr))
1305 V_DISPATCH(pVarResult) = dispatch;
1306 else
1307 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1309 else
1311 ERR("MsiGetSummaryInformation returned %d\n", ret);
1312 return DISP_E_EXCEPTION;
1315 else return DISP_E_MEMBERNOTFOUND;
1316 break;
1318 case DISPID_DATABASE_OPENVIEW:
1319 if (wFlags & DISPATCH_METHOD)
1321 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1322 if (FAILED(hr)) return hr;
1323 V_VT(pVarResult) = VT_DISPATCH;
1324 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1326 if (SUCCEEDED(hr = create_view(msiHandle, &dispatch)))
1327 V_DISPATCH(pVarResult) = dispatch;
1328 else
1329 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1331 else
1333 VariantClear(&varg0);
1334 ERR("MsiDatabaseOpenView returned %d\n", ret);
1335 return DISP_E_EXCEPTION;
1338 else return DISP_E_MEMBERNOTFOUND;
1339 break;
1341 case DISPID_INSTALLER_LASTERRORRECORD:
1342 return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
1343 pVarResult, pExcepInfo,
1344 puArgErr);
1346 default:
1347 return DISP_E_MEMBERNOTFOUND;
1350 VariantClear(&varg1);
1351 VariantClear(&varg0);
1353 return S_OK;
1356 static HRESULT session_invoke(
1357 AutomationObject* This,
1358 DISPID dispIdMember,
1359 REFIID riid,
1360 LCID lcid,
1361 WORD wFlags,
1362 DISPPARAMS* pDispParams,
1363 VARIANT* pVarResult,
1364 EXCEPINFO* pExcepInfo,
1365 UINT* puArgErr)
1367 SessionObject *session = (SessionObject*)This;
1368 WCHAR *szString;
1369 DWORD dwLen = 0;
1370 MSIHANDLE msiHandle;
1371 LANGID langId;
1372 UINT ret;
1373 INSTALLSTATE iInstalled, iAction;
1374 VARIANTARG varg0, varg1;
1375 HRESULT hr;
1377 VariantInit(&varg0);
1378 VariantInit(&varg1);
1380 switch (dispIdMember)
1382 case DISPID_SESSION_INSTALLER:
1383 if (wFlags & DISPATCH_PROPERTYGET) {
1384 V_VT(pVarResult) = VT_DISPATCH;
1385 IDispatch_AddRef(session->installer);
1386 V_DISPATCH(pVarResult) = session->installer;
1388 else return DISP_E_MEMBERNOTFOUND;
1389 break;
1391 case DISPID_SESSION_PROPERTY:
1392 if (wFlags & DISPATCH_PROPERTYGET) {
1393 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1394 if (FAILED(hr)) return hr;
1395 V_VT(pVarResult) = VT_BSTR;
1396 V_BSTR(pVarResult) = NULL;
1397 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1399 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1400 ERR("Out of memory\n");
1401 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1402 V_BSTR(pVarResult) = SysAllocString(szString);
1403 msi_free(szString);
1405 if (ret != ERROR_SUCCESS)
1406 ERR("MsiGetProperty returned %d\n", ret);
1407 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1408 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1409 if (FAILED(hr)) return hr;
1410 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1411 if (FAILED(hr)) {
1412 VariantClear(&varg0);
1413 return hr;
1415 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1417 VariantClear(&varg0);
1418 VariantClear(&varg1);
1419 ERR("MsiSetProperty returned %d\n", ret);
1420 return DISP_E_EXCEPTION;
1423 else return DISP_E_MEMBERNOTFOUND;
1424 break;
1426 case DISPID_SESSION_LANGUAGE:
1427 if (wFlags & DISPATCH_PROPERTYGET) {
1428 langId = MsiGetLanguage(This->msiHandle);
1429 V_VT(pVarResult) = VT_I4;
1430 V_I4(pVarResult) = langId;
1432 else return DISP_E_MEMBERNOTFOUND;
1433 break;
1435 case DISPID_SESSION_MODE:
1436 if (wFlags & DISPATCH_PROPERTYGET) {
1437 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1438 if (FAILED(hr)) return hr;
1439 V_VT(pVarResult) = VT_BOOL;
1440 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0)) ? VARIANT_TRUE : VARIANT_FALSE;
1441 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1442 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1443 if (FAILED(hr)) return hr;
1444 hr = DispGetParam(pDispParams, 1, VT_BOOL, &varg1, puArgErr);
1445 if (FAILED(hr)) return hr;
1446 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1448 ERR("MsiSetMode returned %d\n", ret);
1449 return DISP_E_EXCEPTION;
1452 else return DISP_E_MEMBERNOTFOUND;
1453 break;
1455 case DISPID_SESSION_DATABASE:
1456 if (wFlags & DISPATCH_PROPERTYGET) {
1457 V_VT(pVarResult) = VT_DISPATCH;
1458 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1460 IDispatch *dispatch;
1462 if (SUCCEEDED(hr = create_database(msiHandle, &dispatch)))
1463 V_DISPATCH(pVarResult) = dispatch;
1464 else
1465 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1467 else
1469 ERR("MsiGetActiveDatabase failed\n");
1470 return DISP_E_EXCEPTION;
1473 else return DISP_E_MEMBERNOTFOUND;
1474 break;
1476 case DISPID_SESSION_DOACTION:
1477 if (wFlags & DISPATCH_METHOD) {
1478 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1479 if (FAILED(hr)) return hr;
1480 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1481 V_VT(pVarResult) = VT_I4;
1482 switch (ret)
1484 case ERROR_FUNCTION_NOT_CALLED:
1485 V_I4(pVarResult) = msiDoActionStatusNoAction;
1486 break;
1487 case ERROR_SUCCESS:
1488 V_I4(pVarResult) = msiDoActionStatusSuccess;
1489 break;
1490 case ERROR_INSTALL_USEREXIT:
1491 V_I4(pVarResult) = msiDoActionStatusUserExit;
1492 break;
1493 case ERROR_INSTALL_FAILURE:
1494 V_I4(pVarResult) = msiDoActionStatusFailure;
1495 break;
1496 case ERROR_INSTALL_SUSPEND:
1497 V_I4(pVarResult) = msiDoActionStatusSuspend;
1498 break;
1499 case ERROR_MORE_DATA:
1500 V_I4(pVarResult) = msiDoActionStatusFinished;
1501 break;
1502 case ERROR_INVALID_HANDLE_STATE:
1503 V_I4(pVarResult) = msiDoActionStatusWrongState;
1504 break;
1505 case ERROR_INVALID_DATA:
1506 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1507 break;
1508 default:
1509 VariantClear(&varg0);
1510 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1511 return DISP_E_EXCEPTION;
1514 else return DISP_E_MEMBERNOTFOUND;
1515 break;
1517 case DISPID_SESSION_EVALUATECONDITION:
1518 if (wFlags & DISPATCH_METHOD) {
1519 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1520 if (FAILED(hr)) return hr;
1521 V_VT(pVarResult) = VT_I4;
1522 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1524 else return DISP_E_MEMBERNOTFOUND;
1525 break;
1527 case DISPID_SESSION_MESSAGE:
1528 if(!(wFlags & DISPATCH_METHOD))
1529 return DISP_E_MEMBERNOTFOUND;
1531 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1532 if (FAILED(hr)) return hr;
1533 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1534 if (FAILED(hr)) return hr;
1536 V_VT(pVarResult) = VT_I4;
1537 V_I4(pVarResult) =
1538 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
1539 break;
1541 case DISPID_SESSION_SETINSTALLLEVEL:
1542 if (wFlags & DISPATCH_METHOD) {
1543 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1544 if (FAILED(hr)) return hr;
1545 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1547 ERR("MsiSetInstallLevel returned %d\n", ret);
1548 return DISP_E_EXCEPTION;
1551 else return DISP_E_MEMBERNOTFOUND;
1552 break;
1554 case DISPID_SESSION_FEATURECURRENTSTATE:
1555 if (wFlags & DISPATCH_PROPERTYGET) {
1556 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1557 if (FAILED(hr)) return hr;
1558 V_VT(pVarResult) = VT_I4;
1559 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1560 V_I4(pVarResult) = iInstalled;
1561 else
1563 ERR("MsiGetFeatureState returned %d\n", ret);
1564 V_I4(pVarResult) = msiInstallStateUnknown;
1567 else return DISP_E_MEMBERNOTFOUND;
1568 break;
1570 case DISPID_SESSION_FEATUREREQUESTSTATE:
1571 if (wFlags & DISPATCH_PROPERTYGET) {
1572 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1573 if (FAILED(hr)) return hr;
1574 V_VT(pVarResult) = VT_I4;
1575 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1576 V_I4(pVarResult) = iAction;
1577 else
1579 ERR("MsiGetFeatureState returned %d\n", ret);
1580 V_I4(pVarResult) = msiInstallStateUnknown;
1582 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1583 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1584 if (FAILED(hr)) return hr;
1585 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1586 if (FAILED(hr)) {
1587 VariantClear(&varg0);
1588 return hr;
1590 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1592 VariantClear(&varg0);
1593 ERR("MsiSetFeatureState returned %d\n", ret);
1594 return DISP_E_EXCEPTION;
1597 else return DISP_E_MEMBERNOTFOUND;
1598 break;
1600 default:
1601 return DISP_E_MEMBERNOTFOUND;
1604 VariantClear(&varg1);
1605 VariantClear(&varg0);
1607 return S_OK;
1610 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1611 * registry value type. Used by Installer::RegistryValue. */
1612 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1614 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1615 static const WCHAR szREG_[] = { '(','R','E','G','_','?','?',')',0 };
1616 WCHAR *szString = (WCHAR *)lpData;
1617 LPWSTR szNewString = NULL;
1618 DWORD dwNewSize = 0;
1619 int idx;
1621 switch (dwType)
1623 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1624 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1625 idx = (dwSize/sizeof(WCHAR))-1;
1626 while (idx >= 0 && !szString[idx]) idx--;
1627 for (; idx >= 0; idx--)
1628 if (!szString[idx]) szString[idx] = '\n';
1629 /* fall through */
1630 case REG_SZ:
1631 V_VT(pVarResult) = VT_BSTR;
1632 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1633 break;
1635 case REG_EXPAND_SZ:
1636 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1637 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1638 else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1639 ERR("Out of memory\n");
1640 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1641 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1642 else
1644 V_VT(pVarResult) = VT_BSTR;
1645 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1647 msi_free(szNewString);
1648 break;
1650 case REG_DWORD:
1651 V_VT(pVarResult) = VT_I4;
1652 V_I4(pVarResult) = *((DWORD *)lpData);
1653 break;
1655 case REG_QWORD:
1656 V_VT(pVarResult) = VT_BSTR;
1657 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1658 break;
1660 case REG_BINARY:
1661 V_VT(pVarResult) = VT_BSTR;
1662 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1663 break;
1665 case REG_NONE:
1666 V_VT(pVarResult) = VT_EMPTY;
1667 break;
1669 default:
1670 FIXME("Unhandled registry value type %d\n", dwType);
1674 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1675 DISPPARAMS* pDispParams,
1676 VARIANT* pVarResult,
1677 EXCEPINFO* pExcepInfo,
1678 UINT* puArgErr)
1680 HRESULT hr;
1681 VARIANTARG varg0;
1682 MSIHANDLE hrec;
1684 if (!(wFlags & DISPATCH_METHOD))
1685 return DISP_E_MEMBERNOTFOUND;
1687 VariantInit(&varg0);
1688 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1689 if (FAILED(hr))
1690 return hr;
1692 V_VT(pVarResult) = VT_DISPATCH;
1694 hrec = MsiCreateRecord(V_I4(&varg0));
1695 if (!hrec)
1696 return DISP_E_EXCEPTION;
1698 return create_record(hrec, &V_DISPATCH(pVarResult));
1701 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1702 WORD wFlags,
1703 DISPPARAMS* pDispParams,
1704 VARIANT* pVarResult,
1705 EXCEPINFO* pExcepInfo,
1706 UINT* puArgErr)
1708 UINT ret;
1709 HRESULT hr;
1710 MSIHANDLE hpkg;
1711 IDispatch* dispatch;
1712 VARIANTARG varg0, varg1;
1714 if (!(wFlags & DISPATCH_METHOD))
1715 return DISP_E_MEMBERNOTFOUND;
1717 if (pDispParams->cArgs == 0)
1718 return DISP_E_TYPEMISMATCH;
1720 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1721 return DISP_E_TYPEMISMATCH;
1723 VariantInit(&varg0);
1724 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1725 if (FAILED(hr))
1726 return hr;
1728 VariantInit(&varg1);
1729 if (pDispParams->cArgs == 2)
1731 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1732 if (FAILED(hr))
1733 goto done;
1735 else
1737 V_VT(&varg1) = VT_I4;
1738 V_I4(&varg1) = 0;
1741 V_VT(pVarResult) = VT_DISPATCH;
1743 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1744 if (ret != ERROR_SUCCESS)
1746 hr = DISP_E_EXCEPTION;
1747 goto done;
1750 hr = create_session(hpkg, &This->IDispatch_iface, &dispatch);
1751 if (SUCCEEDED(hr))
1752 V_DISPATCH(pVarResult) = dispatch;
1754 done:
1755 VariantClear(&varg0);
1756 VariantClear(&varg1);
1757 return hr;
1760 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1761 DISPPARAMS* pDispParams,
1762 VARIANT* pVarResult,
1763 EXCEPINFO* pExcepInfo,
1764 UINT* puArgErr)
1766 HRESULT hr;
1767 VARIANTARG varg0;
1769 if (!(wFlags & DISPATCH_METHOD))
1770 return DISP_E_MEMBERNOTFOUND;
1772 VariantInit(&varg0);
1773 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1774 if (FAILED(hr))
1775 return hr;
1777 FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1779 VariantInit(pVarResult);
1781 VariantClear(&varg0);
1782 return S_OK;
1785 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1786 DISPPARAMS* pDispParams,
1787 VARIANT* pVarResult,
1788 EXCEPINFO* pExcepInfo,
1789 UINT* puArgErr)
1791 UINT ret;
1792 HRESULT hr;
1793 MSIHANDLE hdb;
1794 IDispatch* dispatch;
1795 VARIANTARG varg0, varg1;
1797 if (!(wFlags & DISPATCH_METHOD))
1798 return DISP_E_MEMBERNOTFOUND;
1800 VariantInit(&varg0);
1801 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1802 if (FAILED(hr))
1803 return hr;
1805 VariantInit(&varg1);
1806 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1807 if (FAILED(hr))
1808 goto done;
1810 V_VT(pVarResult) = VT_DISPATCH;
1812 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1813 if (ret != ERROR_SUCCESS)
1815 hr = DISP_E_EXCEPTION;
1816 goto done;
1819 hr = create_database(hdb, &dispatch);
1820 if (SUCCEEDED(hr))
1821 V_DISPATCH(pVarResult) = dispatch;
1823 done:
1824 VariantClear(&varg0);
1825 VariantClear(&varg1);
1826 return hr;
1829 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1830 DISPPARAMS* pDispParams,
1831 VARIANT* pVarResult,
1832 EXCEPINFO* pExcepInfo,
1833 UINT* puArgErr)
1835 UINT ret;
1836 HRESULT hr;
1837 MSIHANDLE hsuminfo;
1838 IDispatch *dispatch;
1839 VARIANTARG varg0, varg1;
1841 if (!(wFlags & DISPATCH_PROPERTYGET))
1842 return DISP_E_MEMBERNOTFOUND;
1844 VariantInit(&varg1);
1845 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1846 if (FAILED(hr))
1847 return hr;
1849 VariantInit(&varg0);
1850 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1851 if (FAILED(hr))
1852 return hr;
1854 ret = MsiGetSummaryInformationW(0, V_BSTR(&varg0), V_I4(&varg1), &hsuminfo);
1855 VariantClear(&varg0);
1856 if (ret != ERROR_SUCCESS)
1857 return DISP_E_EXCEPTION;
1859 hr = create_summaryinfo(hsuminfo, &dispatch);
1860 if (FAILED(hr))
1861 return hr;
1863 V_VT(pVarResult) = VT_DISPATCH;
1864 V_DISPATCH(pVarResult) = dispatch;
1865 return S_OK;
1868 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1869 DISPPARAMS* pDispParams,
1870 VARIANT* pVarResult,
1871 EXCEPINFO* pExcepInfo,
1872 UINT* puArgErr)
1874 HRESULT hr;
1875 VARIANTARG varg0;
1876 INSTALLUILEVEL ui;
1878 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1879 return DISP_E_MEMBERNOTFOUND;
1881 if (wFlags & DISPATCH_PROPERTYPUT)
1883 VariantInit(&varg0);
1884 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1885 if (FAILED(hr))
1886 return hr;
1888 ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1889 if (ui == INSTALLUILEVEL_NOCHANGE)
1890 return DISP_E_EXCEPTION;
1892 else if (wFlags & DISPATCH_PROPERTYGET)
1894 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1895 if (ui == INSTALLUILEVEL_NOCHANGE)
1896 return DISP_E_EXCEPTION;
1898 V_VT(pVarResult) = VT_I4;
1899 V_I4(pVarResult) = ui;
1902 return S_OK;
1905 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1906 DISPPARAMS* pDispParams,
1907 VARIANT* pVarResult,
1908 EXCEPINFO* pExcepInfo,
1909 UINT* puArgErr)
1911 if (!(wFlags & DISPATCH_METHOD))
1912 return DISP_E_MEMBERNOTFOUND;
1914 FIXME("\n");
1916 VariantInit(pVarResult);
1917 return S_OK;
1920 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1921 DISPPARAMS* pDispParams,
1922 VARIANT* pVarResult,
1923 EXCEPINFO* pExcepInfo,
1924 UINT* puArgErr)
1926 UINT ret;
1927 HRESULT hr;
1928 VARIANTARG varg0, varg1;
1930 if (!(wFlags & DISPATCH_METHOD))
1931 return DISP_E_MEMBERNOTFOUND;
1933 VariantInit(&varg0);
1934 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1935 if (FAILED(hr))
1936 return hr;
1938 VariantInit(&varg1);
1939 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1940 if (FAILED(hr))
1941 goto done;
1943 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1944 if (ret != ERROR_SUCCESS)
1946 hr = DISP_E_EXCEPTION;
1947 goto done;
1950 done:
1951 VariantClear(&varg0);
1952 VariantClear(&varg1);
1953 return hr;
1956 static HRESULT InstallerImpl_Version(WORD wFlags,
1957 VARIANT* pVarResult,
1958 EXCEPINFO* pExcepInfo,
1959 UINT* puArgErr)
1961 HRESULT hr;
1962 DLLVERSIONINFO verinfo;
1963 WCHAR version[MAX_PATH];
1965 static const WCHAR format[] = {
1966 '%','d','.','%','d','.','%','d','.','%','d',0};
1968 if (!(wFlags & DISPATCH_PROPERTYGET))
1969 return DISP_E_MEMBERNOTFOUND;
1971 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1972 hr = DllGetVersion(&verinfo);
1973 if (FAILED(hr))
1974 return hr;
1976 sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1977 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1979 V_VT(pVarResult) = VT_BSTR;
1980 V_BSTR(pVarResult) = SysAllocString(version);
1981 return S_OK;
1984 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1985 DISPPARAMS* pDispParams,
1986 VARIANT* pVarResult,
1987 EXCEPINFO* pExcepInfo,
1988 UINT* puArgErr)
1990 if (!(wFlags & DISPATCH_METHOD))
1991 return DISP_E_MEMBERNOTFOUND;
1993 FIXME("\n");
1995 VariantInit(pVarResult);
1996 return S_OK;
1999 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
2000 DISPPARAMS* pDispParams,
2001 VARIANT* pVarResult,
2002 EXCEPINFO* pExcepInfo,
2003 UINT* puArgErr)
2005 UINT ret;
2006 HKEY hkey = NULL;
2007 HRESULT hr;
2008 UINT posValue;
2009 DWORD type, size;
2010 LPWSTR szString = NULL;
2011 VARIANTARG varg0, varg1, varg2;
2013 if (!(wFlags & DISPATCH_METHOD))
2014 return DISP_E_MEMBERNOTFOUND;
2016 VariantInit(&varg0);
2017 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
2018 if (FAILED(hr))
2019 return hr;
2021 VariantInit(&varg1);
2022 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2023 if (FAILED(hr))
2024 goto done;
2026 /* Save valuePos so we can save puArgErr if we are unable to do our type
2027 * conversions.
2029 posValue = 2;
2030 VariantInit(&varg2);
2031 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
2032 if (FAILED(hr))
2033 goto done;
2035 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
2036 V_I4(&varg0) <= REG_INDEX_DYN_DATA)
2038 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
2041 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
2043 /* Only VT_EMPTY case can do anything if the key doesn't exist. */
2044 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
2046 hr = DISP_E_BADINDEX;
2047 goto done;
2050 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
2051 switch (V_VT(&varg2))
2053 /* Return VT_BOOL clarifying whether registry key exists or not. */
2054 case VT_EMPTY:
2055 V_VT(pVarResult) = VT_BOOL;
2056 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS) ? VARIANT_TRUE : VARIANT_FALSE;
2057 break;
2059 /* Return the value of specified key if it exists. */
2060 case VT_BSTR:
2061 ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
2062 NULL, NULL, NULL, &size);
2063 if (ret != ERROR_SUCCESS)
2065 hr = DISP_E_BADINDEX;
2066 goto done;
2069 szString = msi_alloc(size);
2070 if (!szString)
2072 hr = E_OUTOFMEMORY;
2073 goto done;
2076 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
2077 &type, (LPBYTE)szString, &size);
2078 if (ret != ERROR_SUCCESS)
2080 msi_free(szString);
2081 hr = DISP_E_BADINDEX;
2082 goto done;
2085 variant_from_registry_value(pVarResult, type,
2086 (LPBYTE)szString, size);
2087 msi_free(szString);
2088 break;
2090 /* Try to make it into VT_I4, can use VariantChangeType for this. */
2091 default:
2092 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
2093 if (FAILED(hr))
2095 if (hr == DISP_E_TYPEMISMATCH)
2096 *puArgErr = posValue;
2098 goto done;
2101 /* Retrieve class name or maximum value name or subkey name size. */
2102 if (!V_I4(&varg2))
2103 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
2104 NULL, NULL, NULL, NULL, NULL, NULL);
2105 else if (V_I4(&varg2) > 0)
2106 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
2107 NULL, NULL, &size, NULL, NULL, NULL);
2108 else /* V_I4(&varg2) < 0 */
2109 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
2110 NULL, NULL, NULL, NULL, NULL, NULL);
2112 if (ret != ERROR_SUCCESS)
2113 goto done;
2115 szString = msi_alloc(++size * sizeof(WCHAR));
2116 if (!szString)
2118 hr = E_OUTOFMEMORY;
2119 goto done;
2122 if (!V_I4(&varg2))
2123 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
2124 NULL, NULL, NULL, NULL, NULL, NULL);
2125 else if (V_I4(&varg2) > 0)
2126 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
2127 &size, 0, 0, NULL, NULL);
2128 else /* V_I4(&varg2) < 0 */
2129 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
2131 if (ret == ERROR_SUCCESS)
2133 V_VT(pVarResult) = VT_BSTR;
2134 V_BSTR(pVarResult) = SysAllocString(szString);
2137 msi_free(szString);
2140 done:
2141 VariantClear(&varg0);
2142 VariantClear(&varg1);
2143 VariantClear(&varg2);
2144 RegCloseKey(hkey);
2145 return hr;
2148 static HRESULT InstallerImpl_Environment(WORD wFlags,
2149 DISPPARAMS* pDispParams,
2150 VARIANT* pVarResult,
2151 EXCEPINFO* pExcepInfo,
2152 UINT* puArgErr)
2154 if (!(wFlags & DISPATCH_METHOD))
2155 return DISP_E_MEMBERNOTFOUND;
2157 FIXME("\n");
2159 VariantInit(pVarResult);
2160 return S_OK;
2163 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2164 DISPPARAMS* pDispParams,
2165 VARIANT* pVarResult,
2166 EXCEPINFO* pExcepInfo,
2167 UINT* puArgErr)
2169 if (!(wFlags & DISPATCH_METHOD))
2170 return DISP_E_MEMBERNOTFOUND;
2172 FIXME("\n");
2174 VariantInit(pVarResult);
2175 return S_OK;
2178 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2179 DISPPARAMS* pDispParams,
2180 VARIANT* pVarResult,
2181 EXCEPINFO* pExcepInfo,
2182 UINT* puArgErr)
2184 if (!(wFlags & DISPATCH_METHOD))
2185 return DISP_E_MEMBERNOTFOUND;
2187 FIXME("\n");
2189 VariantInit(pVarResult);
2190 return S_OK;
2193 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2194 DISPPARAMS* pDispParams,
2195 VARIANT* pVarResult,
2196 EXCEPINFO* pExcepInfo,
2197 UINT* puArgErr)
2199 if (!(wFlags & DISPATCH_METHOD))
2200 return DISP_E_MEMBERNOTFOUND;
2202 FIXME("\n");
2204 VariantInit(pVarResult);
2205 return S_OK;
2208 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2209 DISPPARAMS* pDispParams,
2210 VARIANT* pVarResult,
2211 EXCEPINFO* pExcepInfo,
2212 UINT* puArgErr)
2214 HRESULT hr;
2215 VARIANTARG varg0;
2217 if (!(wFlags & DISPATCH_PROPERTYGET))
2218 return DISP_E_MEMBERNOTFOUND;
2220 VariantInit(&varg0);
2221 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2222 if (FAILED(hr))
2223 return hr;
2225 V_VT(pVarResult) = VT_I4;
2226 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2228 VariantClear(&varg0);
2229 return S_OK;
2232 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2233 DISPPARAMS* pDispParams,
2234 VARIANT* pVarResult,
2235 EXCEPINFO* pExcepInfo,
2236 UINT* puArgErr)
2238 UINT ret;
2239 HRESULT hr;
2240 DWORD size;
2241 LPWSTR str = NULL;
2242 VARIANTARG varg0, varg1;
2244 if (!(wFlags & DISPATCH_PROPERTYGET))
2245 return DISP_E_MEMBERNOTFOUND;
2247 VariantInit(&varg0);
2248 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2249 if (FAILED(hr))
2250 return hr;
2252 VariantInit(&varg1);
2253 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2254 if (FAILED(hr))
2255 goto done;
2257 V_VT(pVarResult) = VT_BSTR;
2258 V_BSTR(pVarResult) = NULL;
2260 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2261 if (ret != ERROR_SUCCESS)
2263 hr = DISP_E_EXCEPTION;
2264 goto done;
2267 str = msi_alloc(++size * sizeof(WCHAR));
2268 if (!str)
2270 hr = E_OUTOFMEMORY;
2271 goto done;
2274 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2275 if (ret != ERROR_SUCCESS)
2277 hr = DISP_E_EXCEPTION;
2278 goto done;
2281 V_BSTR(pVarResult) = SysAllocString(str);
2282 hr = S_OK;
2284 done:
2285 msi_free(str);
2286 VariantClear(&varg0);
2287 VariantClear(&varg1);
2288 return hr;
2291 static HRESULT InstallerImpl_Products(WORD flags,
2292 DISPPARAMS* pDispParams,
2293 VARIANT* result,
2294 EXCEPINFO* pExcepInfo,
2295 UINT* puArgErr)
2297 IDispatch *dispatch;
2298 HRESULT hr;
2300 if (!(flags & DISPATCH_PROPERTYGET))
2301 return DISP_E_MEMBERNOTFOUND;
2303 hr = create_list(NULL, &dispatch);
2304 if (FAILED(hr))
2305 return hr;
2307 V_VT(result) = VT_DISPATCH;
2308 V_DISPATCH(result) = dispatch;
2310 return hr;
2313 static HRESULT InstallerImpl_RelatedProducts(WORD flags,
2314 DISPPARAMS* pDispParams,
2315 VARIANT* result,
2316 EXCEPINFO* pExcepInfo,
2317 UINT* puArgErr)
2319 IDispatch* dispatch;
2320 VARIANTARG related;
2321 HRESULT hr;
2323 if (!(flags & DISPATCH_PROPERTYGET))
2324 return DISP_E_MEMBERNOTFOUND;
2326 VariantInit(&related);
2327 hr = DispGetParam(pDispParams, 0, VT_BSTR, &related, puArgErr);
2328 if (FAILED(hr))
2329 return hr;
2331 hr = create_list(V_BSTR(&related), &dispatch);
2332 VariantClear(&related);
2334 V_VT(result) = VT_DISPATCH;
2335 V_DISPATCH(result) = dispatch;
2337 return hr;
2340 static HRESULT installer_invoke(
2341 AutomationObject* This,
2342 DISPID dispIdMember,
2343 REFIID riid,
2344 LCID lcid,
2345 WORD wFlags,
2346 DISPPARAMS* pDispParams,
2347 VARIANT* pVarResult,
2348 EXCEPINFO* pExcepInfo,
2349 UINT* puArgErr)
2351 switch (dispIdMember)
2353 case DISPID_INSTALLER_CREATERECORD:
2354 return InstallerImpl_CreateRecord(wFlags, pDispParams,
2355 pVarResult, pExcepInfo, puArgErr);
2357 case DISPID_INSTALLER_OPENPACKAGE:
2358 return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2359 pVarResult, pExcepInfo, puArgErr);
2361 case DISPID_INSTALLER_OPENPRODUCT:
2362 return InstallerImpl_OpenProduct(wFlags, pDispParams,
2363 pVarResult, pExcepInfo, puArgErr);
2365 case DISPID_INSTALLER_OPENDATABASE:
2366 return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2367 pVarResult, pExcepInfo, puArgErr);
2369 case DISPID_INSTALLER_SUMMARYINFORMATION:
2370 return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2371 pVarResult, pExcepInfo,
2372 puArgErr);
2374 case DISPID_INSTALLER_UILEVEL:
2375 return InstallerImpl_UILevel(wFlags, pDispParams,
2376 pVarResult, pExcepInfo, puArgErr);
2378 case DISPID_INSTALLER_ENABLELOG:
2379 return InstallerImpl_EnableLog(wFlags, pDispParams,
2380 pVarResult, pExcepInfo, puArgErr);
2382 case DISPID_INSTALLER_INSTALLPRODUCT:
2383 return InstallerImpl_InstallProduct(wFlags, pDispParams,
2384 pVarResult, pExcepInfo,
2385 puArgErr);
2387 case DISPID_INSTALLER_VERSION:
2388 return InstallerImpl_Version(wFlags, pVarResult,
2389 pExcepInfo, puArgErr);
2391 case DISPID_INSTALLER_LASTERRORRECORD:
2392 return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2393 pVarResult, pExcepInfo,
2394 puArgErr);
2396 case DISPID_INSTALLER_REGISTRYVALUE:
2397 return InstallerImpl_RegistryValue(wFlags, pDispParams,
2398 pVarResult, pExcepInfo,
2399 puArgErr);
2401 case DISPID_INSTALLER_ENVIRONMENT:
2402 return InstallerImpl_Environment(wFlags, pDispParams,
2403 pVarResult, pExcepInfo, puArgErr);
2405 case DISPID_INSTALLER_FILEATTRIBUTES:
2406 return InstallerImpl_FileAttributes(wFlags, pDispParams,
2407 pVarResult, pExcepInfo,
2408 puArgErr);
2410 case DISPID_INSTALLER_FILESIZE:
2411 return InstallerImpl_FileSize(wFlags, pDispParams,
2412 pVarResult, pExcepInfo, puArgErr);
2414 case DISPID_INSTALLER_FILEVERSION:
2415 return InstallerImpl_FileVersion(wFlags, pDispParams,
2416 pVarResult, pExcepInfo, puArgErr);
2418 case DISPID_INSTALLER_PRODUCTSTATE:
2419 return InstallerImpl_ProductState(wFlags, pDispParams,
2420 pVarResult, pExcepInfo, puArgErr);
2422 case DISPID_INSTALLER_PRODUCTINFO:
2423 return InstallerImpl_ProductInfo(wFlags, pDispParams,
2424 pVarResult, pExcepInfo, puArgErr);
2426 case DISPID_INSTALLER_PRODUCTS:
2427 return InstallerImpl_Products(wFlags, pDispParams,
2428 pVarResult, pExcepInfo, puArgErr);
2430 case DISPID_INSTALLER_RELATEDPRODUCTS:
2431 return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2432 pVarResult, pExcepInfo,
2433 puArgErr);
2435 default:
2436 return DISP_E_MEMBERNOTFOUND;
2440 HRESULT create_msiserver(IUnknown *outer, void **ppObj)
2442 AutomationObject *installer;
2443 HRESULT hr;
2445 TRACE("(%p %p)\n", outer, ppObj);
2447 if (outer)
2448 return CLASS_E_NOAGGREGATION;
2450 installer = msi_alloc(sizeof(AutomationObject));
2451 if (!installer) return E_OUTOFMEMORY;
2453 hr = init_automation_object(installer, 0, Installer_tid);
2454 if (hr != S_OK)
2456 msi_free(installer);
2457 return hr;
2460 *ppObj = &installer->IDispatch_iface;
2462 return hr;
2465 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp)
2467 SessionObject *session;
2468 HRESULT hr;
2470 session = msi_alloc(sizeof(SessionObject));
2471 if (!session) return E_OUTOFMEMORY;
2473 hr = init_automation_object(&session->autoobj, msiHandle, Session_tid);
2474 if (hr != S_OK)
2476 msi_free(session);
2477 return hr;
2480 session->installer = installer;
2481 *disp = &session->autoobj.IDispatch_iface;
2483 return hr;
2486 static HRESULT create_database(MSIHANDLE msiHandle, IDispatch **dispatch)
2488 AutomationObject *database;
2489 HRESULT hr;
2491 TRACE("(%d %p)\n", msiHandle, dispatch);
2493 database = msi_alloc(sizeof(AutomationObject));
2494 if (!database) return E_OUTOFMEMORY;
2496 hr = init_automation_object(database, msiHandle, Database_tid);
2497 if (hr != S_OK)
2499 msi_free(database);
2500 return hr;
2503 *dispatch = &database->IDispatch_iface;
2505 return hr;
2508 static HRESULT create_view(MSIHANDLE msiHandle, IDispatch **dispatch)
2510 AutomationObject *view;
2511 HRESULT hr;
2513 TRACE("(%d %p)\n", msiHandle, dispatch);
2515 view = msi_alloc(sizeof(AutomationObject));
2516 if (!view) return E_OUTOFMEMORY;
2518 hr = init_automation_object(view, msiHandle, View_tid);
2519 if (hr != S_OK)
2521 msi_free(view);
2522 return hr;
2525 *dispatch = &view->IDispatch_iface;
2527 return hr;
2530 static HRESULT create_summaryinfo(MSIHANDLE msiHandle, IDispatch **disp)
2532 AutomationObject *info;
2533 HRESULT hr;
2535 info = msi_alloc(sizeof(*info));
2536 if (!info) return E_OUTOFMEMORY;
2538 hr = init_automation_object(info, msiHandle, SummaryInfo_tid);
2539 if (hr != S_OK)
2541 msi_free(info);
2542 return hr;
2545 *disp = &info->IDispatch_iface;
2547 return hr;