windows.networking.hostname/tests: Check if passed HSTRING is duplicated.
[wine.git] / dlls / msi / automation.c
blob36891cc62dad12b85145c82afde1ebd7c4ef074a
1 /*
2 * Implementation of OLE Automation for Microsoft Installer (msi.dll)
4 * Copyright 2007 Misha Koshelev
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "msidefs.h"
30 #include "msipriv.h"
31 #include "activscp.h"
32 #include "oleauto.h"
33 #include "shlwapi.h"
34 #include "wine/debug.h"
36 #include "msiserver.h"
37 #include "msiserver_dispids.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41 #define REG_INDEX_CLASSES_ROOT 0
42 #define REG_INDEX_DYN_DATA 6
44 struct automation_object;
46 struct tid_id
48 REFIID riid;
49 /* function that is called from AutomationObject::Invoke, specific to this type of object */
50 HRESULT (*fn_invoke)(struct automation_object *, DISPID, REFIID, LCID, WORD, DISPPARAMS *, VARIANT *,
51 EXCEPINFO *, UINT *);
52 /* function that is called from AutomationObject::Release when the object is being freed
53 to free any private data structures (or NULL) */
54 void (*fn_free)(struct automation_object *);
57 static HRESULT database_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
58 static HRESULT installer_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
59 static HRESULT record_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
60 static HRESULT session_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
61 static HRESULT list_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
62 static void list_free(struct automation_object*);
63 static HRESULT summaryinfo_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
64 static HRESULT view_invoke(struct automation_object*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
66 static struct tid_id tid_ids[] =
68 { &DIID_Database, database_invoke },
69 { &DIID_Installer, installer_invoke },
70 { &DIID_Record, record_invoke },
71 { &DIID_Session, session_invoke },
72 { &DIID_StringList, list_invoke, list_free },
73 { &DIID_SummaryInfo, summaryinfo_invoke },
74 { &DIID_View, view_invoke }
77 static ITypeLib *typelib;
78 static ITypeInfo *typeinfos[LAST_tid];
80 static const IID *get_riid_from_tid(tid_t tid)
82 return tid_ids[tid].riid;
85 HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo)
87 HRESULT hr;
89 if (!typelib)
91 ITypeLib *lib;
93 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, LOCALE_NEUTRAL, &lib);
94 if (FAILED(hr)) {
95 hr = LoadTypeLib(L"msiserver.tlb", &lib);
96 if (FAILED(hr)) {
97 ERR("Could not load msiserver.tlb\n");
98 return hr;
102 if (InterlockedCompareExchangePointer((void**)&typelib, lib, NULL))
103 ITypeLib_Release(lib);
106 if (!typeinfos[tid])
108 ITypeInfo *ti;
110 hr = ITypeLib_GetTypeInfoOfGuid(typelib, get_riid_from_tid(tid), &ti);
111 if (FAILED(hr)) {
112 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(get_riid_from_tid(tid)));
113 return hr;
116 if(InterlockedCompareExchangePointer((void**)(typeinfos+tid), ti, NULL))
117 ITypeInfo_Release(ti);
120 *typeinfo = typeinfos[tid];
121 return S_OK;
124 void release_typelib(void)
126 unsigned i;
128 for (i = 0; i < ARRAY_SIZE(typeinfos); i++)
129 if (typeinfos[i])
130 ITypeInfo_Release(typeinfos[i]);
132 if (typelib)
133 ITypeLib_Release(typelib);
137 * struct automation_object - "base" class for all automation objects. For each interface, we implement Invoke
138 * function called from AutomationObject::Invoke.
140 struct automation_object
142 IDispatch IDispatch_iface;
143 IProvideMultipleClassInfo IProvideMultipleClassInfo_iface;
144 LONG ref;
146 /* type id for this class */
147 tid_t tid;
149 /* The MSI handle of the current object */
150 MSIHANDLE msiHandle;
153 struct list_object
155 struct automation_object autoobj;
156 int count;
157 VARIANT *data;
160 static HRESULT create_database(MSIHANDLE, IDispatch**);
161 static HRESULT create_list_enumerator(struct list_object *, void **);
162 static HRESULT create_summaryinfo(MSIHANDLE, IDispatch**);
163 static HRESULT create_view(MSIHANDLE, IDispatch**);
165 /* struct list_enumerator - IEnumVARIANT implementation for MSI automation lists */
166 struct list_enumerator
168 IEnumVARIANT IEnumVARIANT_iface;
169 LONG ref;
171 /* Current position and pointer to struct automation_object that stores actual data */
172 ULONG pos;
173 struct list_object *list;
176 struct session_object
178 struct automation_object autoobj;
179 IDispatch *installer;
182 static inline struct automation_object *impl_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
184 return CONTAINING_RECORD(iface, struct automation_object, IProvideMultipleClassInfo_iface);
187 static inline struct automation_object *impl_from_IDispatch( IDispatch *iface )
189 return CONTAINING_RECORD(iface, struct automation_object, IDispatch_iface);
192 /* AutomationObject methods */
193 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
195 struct automation_object *This = impl_from_IDispatch(iface);
197 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
199 if (ppvObject == NULL)
200 return E_INVALIDARG;
202 *ppvObject = 0;
204 if (IsEqualGUID(riid, &IID_IUnknown) ||
205 IsEqualGUID(riid, &IID_IDispatch) ||
206 IsEqualGUID(riid, get_riid_from_tid(This->tid)))
207 *ppvObject = &This->IDispatch_iface;
208 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
209 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
210 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
211 *ppvObject = &This->IProvideMultipleClassInfo_iface;
212 else
214 TRACE("() : asking for unsupported interface %s\n", debugstr_guid(riid));
215 return E_NOINTERFACE;
218 IDispatch_AddRef(iface);
220 return S_OK;
223 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
225 struct automation_object *This = impl_from_IDispatch(iface);
227 TRACE("(%p/%p)\n", iface, This);
229 return InterlockedIncrement(&This->ref);
232 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
234 struct automation_object *This = impl_from_IDispatch(iface);
235 ULONG ref = InterlockedDecrement(&This->ref);
237 TRACE("(%p/%p)\n", iface, This);
239 if (!ref)
241 if (tid_ids[This->tid].fn_free) tid_ids[This->tid].fn_free(This);
242 MsiCloseHandle(This->msiHandle);
243 free(This);
246 return ref;
249 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
250 IDispatch* iface,
251 UINT* pctinfo)
253 struct automation_object *This = impl_from_IDispatch(iface);
255 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
256 *pctinfo = 1;
257 return S_OK;
260 static HRESULT WINAPI AutomationObject_GetTypeInfo(
261 IDispatch* iface,
262 UINT iTInfo,
263 LCID lcid,
264 ITypeInfo** ppTInfo)
266 struct automation_object *This = impl_from_IDispatch(iface);
267 HRESULT hr;
269 TRACE( "(%p/%p)->(%u, %ld, %p)\n", iface, This, iTInfo, lcid, ppTInfo );
271 hr = get_typeinfo(This->tid, ppTInfo);
272 if (FAILED(hr))
273 return hr;
275 ITypeInfo_AddRef(*ppTInfo);
276 return hr;
279 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
280 IDispatch* iface,
281 REFIID riid,
282 LPOLESTR* rgszNames,
283 UINT cNames,
284 LCID lcid,
285 DISPID* rgDispId)
287 struct automation_object *This = impl_from_IDispatch(iface);
288 ITypeInfo *ti;
289 HRESULT hr;
291 TRACE("(%p/%p)->(%s, %p, %u, %ld, %p)\n", iface, This,
292 debugstr_guid(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 struct automation_object *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)->(%ld, %s, %ld, %d, %p, %p, %p, %p)\n", iface, This,
336 dispIdMember, debugstr_guid(riid), lcid, wFlags,
337 pDispParams, pVarResult, pExcepInfo, puArgErr);
339 if (!IsEqualIID(riid, &IID_NULL))
341 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
342 return DISP_E_UNKNOWNNAME;
345 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
347 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
348 return DISP_E_PARAMNOTOPTIONAL;
351 /* This simplifies our individual object invocation functions */
352 if (puArgErr == NULL) puArgErr = &uArgErr;
353 if (pVarResult == NULL) pVarResult = &varResultDummy;
355 hr = get_typeinfo(This->tid, &ti);
356 if (FAILED(hr))
357 return hr;
359 /* Assume return type is void unless determined otherwise */
360 VariantInit(pVarResult);
362 /* If we are tracing, we want to see the name of the member we are invoking */
363 if (TRACE_ON(msi))
365 ITypeInfo_GetDocumentation(ti, dispIdMember, &bstrName, NULL, NULL, NULL);
366 TRACE("method %ld, %s\n", dispIdMember, debugstr_w(bstrName));
369 hr = tid_ids[This->tid].fn_invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
371 if (hr == DISP_E_MEMBERNOTFOUND) {
372 if (bstrName == NULL) ITypeInfo_GetDocumentation(ti, dispIdMember, &bstrName, NULL, NULL, NULL);
373 FIXME("method %ld, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags,
374 debugstr_guid(get_riid_from_tid(This->tid)));
376 else if (pExcepInfo &&
377 (hr == DISP_E_PARAMNOTFOUND ||
378 hr == DISP_E_EXCEPTION)) {
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 %ld\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)], L",");
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(L"Msi API Error");
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 %#lx, %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 struct automation_object *This = impl_from_IProvideMultipleClassInfo(iface);
442 return IDispatch_QueryInterface(&This->IDispatch_iface, riid, ppvoid);
445 static ULONG WINAPI ProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
447 struct automation_object *This = impl_from_IProvideMultipleClassInfo(iface);
448 return IDispatch_AddRef(&This->IDispatch_iface);
451 static ULONG WINAPI ProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
453 struct automation_object *This = impl_from_IProvideMultipleClassInfo(iface);
454 return IDispatch_Release(&This->IDispatch_iface);
457 static HRESULT WINAPI ProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
459 struct automation_object *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 struct automation_object *This = impl_from_IProvideMultipleClassInfo(iface);
474 TRACE("(%p/%p)->(%lu, %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 struct automation_object *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 struct automation_object *This = impl_from_IProvideMultipleClassInfo(iface);
504 TRACE("(%p/%p)->(%lu, %#lx, %p, %p, %p, %p, %p)\n", iface, This, iti, dwFlags, ti, pdwTIFlags, pcdispidReserved,
505 piidPrimary, piidSource);
507 if (iti != 0)
508 return E_INVALIDARG;
510 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
512 HRESULT hr = get_typeinfo(This->tid, ti);
513 if (FAILED(hr))
514 return hr;
516 ITypeInfo_AddRef(*ti);
519 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
521 *pdwTIFlags = 0;
522 *pcdispidReserved = 0;
525 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY)
526 *piidPrimary = *get_riid_from_tid(This->tid);
528 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE)
529 *piidSource = *get_riid_from_tid(This->tid);
531 return S_OK;
534 static const IProvideMultipleClassInfoVtbl ProvideMultipleClassInfoVtbl =
536 ProvideMultipleClassInfo_QueryInterface,
537 ProvideMultipleClassInfo_AddRef,
538 ProvideMultipleClassInfo_Release,
539 ProvideMultipleClassInfo_GetClassInfo,
540 ProvideMultipleClassInfo_GetGUID,
541 ProvideMultipleClassInfo_GetMultiTypeInfoCount,
542 ProvideMultipleClassInfo_GetInfoOfIndex
545 static void init_automation_object(struct automation_object *This, MSIHANDLE msiHandle, tid_t tid)
547 TRACE("%p, %lu, %s\n", This, msiHandle, debugstr_guid(get_riid_from_tid(tid)));
549 This->IDispatch_iface.lpVtbl = &AutomationObjectVtbl;
550 This->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl;
551 This->ref = 1;
552 This->msiHandle = msiHandle;
553 This->tid = tid;
557 * ListEnumerator methods
560 static inline struct list_enumerator *impl_from_IEnumVARIANT(IEnumVARIANT* iface)
562 return CONTAINING_RECORD(iface, struct list_enumerator, IEnumVARIANT_iface);
565 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid,
566 void** ppvObject)
568 struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
570 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
572 if (ppvObject == NULL)
573 return E_INVALIDARG;
575 *ppvObject = 0;
577 if (IsEqualGUID(riid, &IID_IUnknown) ||
578 IsEqualGUID(riid, &IID_IEnumVARIANT))
580 *ppvObject = &This->IEnumVARIANT_iface;
582 else
584 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
585 return E_NOINTERFACE;
588 IEnumVARIANT_AddRef(iface);
589 return S_OK;
592 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
594 struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
596 TRACE("(%p/%p)\n", iface, This);
598 return InterlockedIncrement(&This->ref);
601 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
603 struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
604 ULONG ref = InterlockedDecrement(&This->ref);
606 TRACE("(%p/%p)\n", iface, This);
608 if (!ref)
610 if (This->list) IDispatch_Release(&This->list->autoobj.IDispatch_iface);
611 free(This);
614 return ref;
617 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar,
618 ULONG* fetched)
620 struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
621 ULONG i, local;
623 TRACE("%p, %lu, %p, %p\n", iface, celt, rgVar, fetched);
625 if (fetched) *fetched = 0;
627 if (!rgVar)
628 return S_FALSE;
630 for (local = 0; local < celt; local++)
631 VariantInit(&rgVar[local]);
633 for (i = This->pos, local = 0; i < This->list->count && local < celt; i++, local++)
634 VariantCopy(&rgVar[local], &This->list->data[i]);
636 if (fetched) *fetched = local;
637 This->pos = i;
639 return (local < celt) ? S_FALSE : S_OK;
642 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
644 struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
646 TRACE("%p, %lu\n", iface, celt);
648 This->pos += celt;
649 if (This->pos >= This->list->count)
651 This->pos = This->list->count;
652 return S_FALSE;
655 return S_OK;
658 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
660 struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
662 TRACE("(%p)\n", iface);
664 This->pos = 0;
665 return S_OK;
668 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
670 struct list_enumerator *This = impl_from_IEnumVARIANT(iface);
671 HRESULT hr;
673 TRACE("(%p,%p)\n", iface, ppEnum);
675 if (ppEnum == NULL)
676 return S_FALSE;
678 *ppEnum = NULL;
679 hr = create_list_enumerator(This->list, (LPVOID *)ppEnum);
680 if (FAILED(hr))
682 if (*ppEnum) IEnumVARIANT_Release(*ppEnum);
683 return hr;
686 return S_OK;
689 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
691 ListEnumerator_QueryInterface,
692 ListEnumerator_AddRef,
693 ListEnumerator_Release,
694 ListEnumerator_Next,
695 ListEnumerator_Skip,
696 ListEnumerator_Reset,
697 ListEnumerator_Clone
700 /* Create a list enumerator, placing the result in the pointer ppObj. */
701 static HRESULT create_list_enumerator(struct list_object *list, void **ppObj)
703 struct list_enumerator *object;
705 TRACE("(%p, %p)\n", list, ppObj);
707 object = malloc(sizeof(*object));
709 /* Set all the VTable references */
710 object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
711 object->ref = 1;
713 /* Store data that was passed */
714 object->pos = 0;
715 object->list = list;
716 if (list) IDispatch_AddRef(&list->autoobj.IDispatch_iface);
718 *ppObj = object;
719 return S_OK;
723 * Individual Object Invocation Functions
726 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
727 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
728 using DispGetParam/VariantChangeType. */
729 static HRESULT DispGetParam_CopyOnly(
730 DISPPARAMS *pdispparams, /* [in] Parameter list */
731 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
732 VARIANT *pvarResult) /* [out] Destination for resulting variant */
734 /* position is counted backwards */
735 UINT pos;
737 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
738 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
739 if (*position < pdispparams->cArgs) {
740 /* positional arg? */
741 pos = pdispparams->cArgs - *position - 1;
742 } else {
743 /* FIXME: is this how to handle named args? */
744 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
745 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
747 if (pos==pdispparams->cNamedArgs)
748 return DISP_E_PARAMNOTFOUND;
750 *position = pos;
751 return VariantCopyInd(pvarResult,
752 &pdispparams->rgvarg[pos]);
755 static HRESULT summaryinfo_invoke(
756 struct automation_object *This,
757 DISPID dispIdMember,
758 REFIID riid,
759 LCID lcid,
760 WORD wFlags,
761 DISPPARAMS* pDispParams,
762 VARIANT* pVarResult,
763 EXCEPINFO* pExcepInfo,
764 UINT* puArgErr)
766 UINT ret;
767 VARIANTARG varg0, varg1;
768 FILETIME ft, ftlocal;
769 SYSTEMTIME st;
770 HRESULT hr;
772 VariantInit(&varg0);
773 VariantInit(&varg1);
775 switch (dispIdMember)
777 case DISPID_SUMMARYINFO_PROPERTY:
778 if (wFlags & DISPATCH_PROPERTYGET)
780 UINT type;
781 INT value;
782 DWORD size = 0;
783 DATE date;
784 LPWSTR str;
786 static WCHAR szEmpty[] = L"";
788 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
789 if (FAILED(hr)) return hr;
790 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
791 &ft, szEmpty, &size);
792 if (ret != ERROR_SUCCESS &&
793 ret != ERROR_MORE_DATA)
795 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
796 return DISP_E_EXCEPTION;
799 switch (type)
801 case VT_EMPTY:
802 break;
804 case VT_I2:
805 case VT_I4:
806 V_VT(pVarResult) = VT_I4;
807 V_I4(pVarResult) = value;
808 break;
810 case VT_LPSTR:
811 if (!(str = malloc(++size * sizeof(WCHAR))))
812 ERR("Out of memory\n");
813 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
814 NULL, str, &size)) != ERROR_SUCCESS)
815 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
816 else
818 V_VT(pVarResult) = VT_BSTR;
819 V_BSTR(pVarResult) = SysAllocString(str);
821 free(str);
822 break;
824 case VT_FILETIME:
825 FileTimeToLocalFileTime(&ft, &ftlocal);
826 FileTimeToSystemTime(&ftlocal, &st);
827 SystemTimeToVariantTime(&st, &date);
829 V_VT(pVarResult) = VT_DATE;
830 V_DATE(pVarResult) = date;
831 break;
833 default:
834 ERR("Unhandled variant type %d\n", type);
837 else if (wFlags & DISPATCH_PROPERTYPUT)
839 UINT posValue = DISPID_PROPERTYPUT;
841 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
842 if (FAILED(hr)) return hr;
843 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
844 if (FAILED(hr))
846 *puArgErr = posValue;
847 return hr;
850 switch (V_VT(&varg1))
852 case VT_I2:
853 case VT_I4:
854 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
855 break;
857 case VT_DATE:
858 VariantTimeToSystemTime(V_DATE(&varg1), &st);
859 SystemTimeToFileTime(&st, &ftlocal);
860 LocalFileTimeToFileTime(&ftlocal, &ft);
861 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
862 break;
864 case VT_BSTR:
865 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
866 break;
868 default:
869 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
870 VariantClear(&varg1);
871 return DISP_E_EXCEPTION;
874 if (ret != ERROR_SUCCESS)
876 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
877 return DISP_E_EXCEPTION;
880 else return DISP_E_MEMBERNOTFOUND;
881 break;
883 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
884 if (wFlags & DISPATCH_PROPERTYGET) {
885 UINT count;
886 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
887 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
888 else
890 V_VT(pVarResult) = VT_I4;
891 V_I4(pVarResult) = count;
894 else return DISP_E_MEMBERNOTFOUND;
895 break;
897 default:
898 return DISP_E_MEMBERNOTFOUND;
901 VariantClear(&varg1);
902 VariantClear(&varg0);
904 return S_OK;
907 static HRESULT record_invoke(
908 struct automation_object *This,
909 DISPID dispIdMember,
910 REFIID riid,
911 LCID lcid,
912 WORD wFlags,
913 DISPPARAMS* pDispParams,
914 VARIANT* pVarResult,
915 EXCEPINFO* pExcepInfo,
916 UINT* puArgErr)
918 WCHAR *szString;
919 DWORD dwLen = 0;
920 UINT ret;
921 VARIANTARG varg0, varg1;
922 HRESULT hr;
924 VariantInit(&varg0);
925 VariantInit(&varg1);
927 switch (dispIdMember)
929 case DISPID_RECORD_FIELDCOUNT:
930 if (wFlags & DISPATCH_PROPERTYGET) {
931 V_VT(pVarResult) = VT_I4;
932 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
934 else return DISP_E_MEMBERNOTFOUND;
935 break;
937 case DISPID_RECORD_STRINGDATA:
938 if (wFlags & DISPATCH_PROPERTYGET) {
939 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
940 if (FAILED(hr)) return hr;
941 V_VT(pVarResult) = VT_BSTR;
942 V_BSTR(pVarResult) = NULL;
943 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
945 if (!(szString = malloc((++dwLen) * sizeof(WCHAR))))
946 ERR("Out of memory\n");
947 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
948 V_BSTR(pVarResult) = SysAllocString(szString);
949 free(szString);
951 if (ret != ERROR_SUCCESS)
952 ERR("MsiRecordGetString returned %d\n", ret);
953 } else if (wFlags & DISPATCH_PROPERTYPUT) {
954 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
955 if (FAILED(hr)) return hr;
956 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
957 if (FAILED(hr)) return hr;
958 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
960 VariantClear(&varg1);
961 ERR("MsiRecordSetString returned %d\n", ret);
962 return DISP_E_EXCEPTION;
965 else return DISP_E_MEMBERNOTFOUND;
966 break;
968 case DISPID_RECORD_INTEGERDATA:
969 if (wFlags & DISPATCH_PROPERTYGET) {
970 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
971 if (FAILED(hr)) return hr;
972 V_VT(pVarResult) = VT_I4;
973 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
974 } else if (wFlags & DISPATCH_PROPERTYPUT) {
975 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
976 if (FAILED(hr)) return hr;
977 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
978 if (FAILED(hr)) return hr;
979 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
981 ERR("MsiRecordSetInteger returned %d\n", ret);
982 return DISP_E_EXCEPTION;
985 else return DISP_E_MEMBERNOTFOUND;
986 break;
988 default:
989 return DISP_E_MEMBERNOTFOUND;
992 VariantClear(&varg1);
993 VariantClear(&varg0);
995 return S_OK;
998 static HRESULT create_record(MSIHANDLE msiHandle, IDispatch **disp)
1000 struct automation_object *record;
1002 record = malloc(sizeof(*record));
1003 if (!record) return E_OUTOFMEMORY;
1005 init_automation_object(record, msiHandle, Record_tid);
1007 *disp = &record->IDispatch_iface;
1009 return S_OK;
1012 static HRESULT list_invoke(
1013 struct automation_object *This,
1014 DISPID dispIdMember,
1015 REFIID riid,
1016 LCID lcid,
1017 WORD wFlags,
1018 DISPPARAMS* pDispParams,
1019 VARIANT* pVarResult,
1020 EXCEPINFO* pExcepInfo,
1021 UINT* puArgErr)
1023 struct list_object *list = CONTAINING_RECORD(This, struct list_object, autoobj);
1024 IUnknown *pUnk = NULL;
1025 HRESULT hr;
1027 switch (dispIdMember)
1029 case DISPID_LIST__NEWENUM:
1030 if (wFlags & DISPATCH_METHOD) {
1031 V_VT(pVarResult) = VT_UNKNOWN;
1032 if (SUCCEEDED(hr = create_list_enumerator(list, (LPVOID *)&pUnk)))
1033 V_UNKNOWN(pVarResult) = pUnk;
1034 else
1035 ERR("failed to create IEnumVARIANT object, hresult %#lx\n", hr);
1037 else return DISP_E_MEMBERNOTFOUND;
1038 break;
1040 case DISPID_LIST_ITEM:
1041 if (wFlags & DISPATCH_PROPERTYGET) {
1042 VARIANTARG index;
1044 VariantInit(&index);
1045 hr = DispGetParam(pDispParams, 0, VT_I4, &index, puArgErr);
1046 if (FAILED(hr)) return hr;
1047 if (V_I4(&index) < 0 || V_I4(&index) >= list->count)
1048 return DISP_E_BADINDEX;
1049 VariantCopy(pVarResult, &list->data[V_I4(&index)]);
1051 else return DISP_E_MEMBERNOTFOUND;
1052 break;
1054 case DISPID_LIST_COUNT:
1055 if (wFlags & DISPATCH_PROPERTYGET) {
1056 V_VT(pVarResult) = VT_I4;
1057 V_I4(pVarResult) = list->count;
1059 else return DISP_E_MEMBERNOTFOUND;
1060 break;
1062 default:
1063 return DISP_E_MEMBERNOTFOUND;
1066 return S_OK;
1069 static void list_free(struct automation_object *This)
1071 struct list_object *list = CONTAINING_RECORD(This, struct list_object, autoobj);
1072 int i;
1074 for (i = 0; i < list->count; i++)
1075 VariantClear(&list->data[i]);
1076 free(list->data);
1079 static HRESULT get_products_count(const WCHAR *product, int *len)
1081 int i = 0;
1083 while (1)
1085 WCHAR dataW[GUID_SIZE];
1086 UINT ret;
1088 /* all or related only */
1089 if (product)
1090 ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1091 else
1092 ret = MsiEnumProductsW(i, dataW);
1094 if (ret == ERROR_NO_MORE_ITEMS) break;
1096 if (ret != ERROR_SUCCESS)
1097 return DISP_E_EXCEPTION;
1099 i++;
1102 *len = i;
1104 return S_OK;
1107 static HRESULT create_list(const WCHAR *product, IDispatch **dispatch)
1109 struct list_object *list;
1110 HRESULT hr;
1111 int i;
1113 list = calloc(1, sizeof(*list));
1114 if (!list) return E_OUTOFMEMORY;
1116 init_automation_object(&list->autoobj, 0, StringList_tid);
1118 *dispatch = &list->autoobj.IDispatch_iface;
1120 hr = get_products_count(product, &list->count);
1121 if (hr != S_OK)
1123 IDispatch_Release(*dispatch);
1124 return hr;
1127 list->data = malloc(list->count * sizeof(VARIANT));
1128 if (!list->data)
1130 IDispatch_Release(*dispatch);
1131 return E_OUTOFMEMORY;
1134 for (i = 0; i < list->count; i++)
1136 WCHAR dataW[GUID_SIZE];
1137 UINT ret;
1139 /* all or related only */
1140 if (product)
1141 ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1142 else
1143 ret = MsiEnumProductsW(i, dataW);
1145 if (ret == ERROR_NO_MORE_ITEMS) break;
1147 V_VT(&list->data[i]) = VT_BSTR;
1148 V_BSTR(&list->data[i]) = SysAllocString(dataW);
1151 return S_OK;
1154 static HRESULT view_invoke(
1155 struct automation_object *This,
1156 DISPID dispIdMember,
1157 REFIID riid,
1158 LCID lcid,
1159 WORD wFlags,
1160 DISPPARAMS* pDispParams,
1161 VARIANT* pVarResult,
1162 EXCEPINFO* pExcepInfo,
1163 UINT* puArgErr)
1165 MSIHANDLE msiHandle;
1166 UINT ret;
1167 VARIANTARG varg0, varg1;
1168 HRESULT hr;
1170 VariantInit(&varg0);
1171 VariantInit(&varg1);
1173 switch (dispIdMember)
1175 case DISPID_VIEW_EXECUTE:
1176 if (wFlags & DISPATCH_METHOD)
1178 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1179 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1180 MsiViewExecute(This->msiHandle, ((struct automation_object *)V_DISPATCH(&varg0))->msiHandle);
1181 else
1182 MsiViewExecute(This->msiHandle, 0);
1184 else return DISP_E_MEMBERNOTFOUND;
1185 break;
1187 case DISPID_VIEW_FETCH:
1188 if (wFlags & DISPATCH_METHOD)
1190 V_VT(pVarResult) = VT_DISPATCH;
1191 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1193 if (FAILED(hr = create_record(msiHandle, &V_DISPATCH(pVarResult))))
1194 ERR("failed to create Record object, hresult %#lx\n", hr);
1196 else if (ret == ERROR_NO_MORE_ITEMS)
1197 V_DISPATCH(pVarResult) = NULL;
1198 else
1200 ERR("MsiViewFetch returned %d\n", ret);
1201 return DISP_E_EXCEPTION;
1204 else return DISP_E_MEMBERNOTFOUND;
1205 break;
1207 case DISPID_VIEW_MODIFY:
1208 if (wFlags & DISPATCH_METHOD)
1210 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1211 if (FAILED(hr)) return hr;
1212 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1213 if (FAILED(hr)) return hr;
1214 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1215 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0),
1216 ((struct automation_object *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1218 VariantClear(&varg1);
1219 ERR("MsiViewModify returned %d\n", ret);
1220 return DISP_E_EXCEPTION;
1223 else return DISP_E_MEMBERNOTFOUND;
1224 break;
1226 case DISPID_VIEW_CLOSE:
1227 if (wFlags & DISPATCH_METHOD)
1229 MsiViewClose(This->msiHandle);
1231 else return DISP_E_MEMBERNOTFOUND;
1232 break;
1234 default:
1235 return DISP_E_MEMBERNOTFOUND;
1238 VariantClear(&varg1);
1239 VariantClear(&varg0);
1241 return S_OK;
1244 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
1245 DISPPARAMS* pDispParams,
1246 VARIANT* pVarResult,
1247 EXCEPINFO* pExcepInfo,
1248 UINT* puArgErr)
1250 if (!(wFlags & DISPATCH_METHOD))
1251 return DISP_E_MEMBERNOTFOUND;
1253 FIXME("\n");
1255 VariantInit(pVarResult);
1256 return S_OK;
1259 HRESULT database_invoke(
1260 struct automation_object *This,
1261 DISPID dispIdMember,
1262 REFIID riid,
1263 LCID lcid,
1264 WORD wFlags,
1265 DISPPARAMS* pDispParams,
1266 VARIANT* pVarResult,
1267 EXCEPINFO* pExcepInfo,
1268 UINT* puArgErr)
1270 IDispatch *dispatch = NULL;
1271 MSIHANDLE msiHandle;
1272 UINT ret;
1273 VARIANTARG varg0, varg1;
1274 HRESULT hr;
1276 VariantInit(&varg0);
1277 VariantInit(&varg1);
1279 switch (dispIdMember)
1281 case DISPID_DATABASE_SUMMARYINFORMATION:
1282 if (wFlags & DISPATCH_PROPERTYGET)
1284 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1285 if (FAILED(hr))
1286 V_I4(&varg0) = 0;
1288 V_VT(pVarResult) = VT_DISPATCH;
1289 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1291 hr = create_summaryinfo(msiHandle, &dispatch);
1292 if (SUCCEEDED(hr))
1293 V_DISPATCH(pVarResult) = dispatch;
1294 else
1295 ERR("failed to create SummaryInfo object: %#lx\n", hr);
1297 else
1299 ERR("MsiGetSummaryInformation returned %d\n", ret);
1300 return DISP_E_EXCEPTION;
1303 else return DISP_E_MEMBERNOTFOUND;
1304 break;
1306 case DISPID_DATABASE_OPENVIEW:
1307 if (wFlags & DISPATCH_METHOD)
1309 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1310 if (FAILED(hr)) return hr;
1311 V_VT(pVarResult) = VT_DISPATCH;
1312 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1314 if (SUCCEEDED(hr = create_view(msiHandle, &dispatch)))
1315 V_DISPATCH(pVarResult) = dispatch;
1316 else
1317 ERR("failed to create View object, hresult %#lx\n", hr);
1319 else
1321 VariantClear(&varg0);
1322 ERR("MsiDatabaseOpenView returned %d\n", ret);
1323 return DISP_E_EXCEPTION;
1326 else return DISP_E_MEMBERNOTFOUND;
1327 break;
1329 case DISPID_INSTALLER_LASTERRORRECORD:
1330 return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
1331 pVarResult, pExcepInfo,
1332 puArgErr);
1334 default:
1335 return DISP_E_MEMBERNOTFOUND;
1338 VariantClear(&varg1);
1339 VariantClear(&varg0);
1341 return S_OK;
1344 static HRESULT session_invoke(
1345 struct automation_object *This,
1346 DISPID dispIdMember,
1347 REFIID riid,
1348 LCID lcid,
1349 WORD wFlags,
1350 DISPPARAMS* pDispParams,
1351 VARIANT* pVarResult,
1352 EXCEPINFO* pExcepInfo,
1353 UINT* puArgErr)
1355 struct session_object *session = CONTAINING_RECORD(This, struct session_object, autoobj);
1356 WCHAR *szString;
1357 DWORD dwLen = 0;
1358 MSIHANDLE msiHandle;
1359 LANGID langId;
1360 UINT ret;
1361 INSTALLSTATE iInstalled, iAction;
1362 VARIANTARG varg0, varg1;
1363 HRESULT hr;
1365 VariantInit(&varg0);
1366 VariantInit(&varg1);
1368 switch (dispIdMember)
1370 case DISPID_SESSION_INSTALLER:
1371 if (wFlags & DISPATCH_PROPERTYGET) {
1372 V_VT(pVarResult) = VT_DISPATCH;
1373 IDispatch_AddRef(session->installer);
1374 V_DISPATCH(pVarResult) = session->installer;
1376 else return DISP_E_MEMBERNOTFOUND;
1377 break;
1379 case DISPID_SESSION_PROPERTY:
1380 if (wFlags & DISPATCH_PROPERTYGET) {
1381 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1382 if (FAILED(hr)) return hr;
1383 V_VT(pVarResult) = VT_BSTR;
1384 V_BSTR(pVarResult) = NULL;
1385 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1387 if (!(szString = malloc((++dwLen) * sizeof(WCHAR))))
1388 ERR("Out of memory\n");
1389 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1390 V_BSTR(pVarResult) = SysAllocString(szString);
1391 free(szString);
1393 if (ret != ERROR_SUCCESS)
1394 ERR("MsiGetProperty returned %d\n", ret);
1395 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1396 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1397 if (FAILED(hr)) return hr;
1398 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1399 if (FAILED(hr)) {
1400 VariantClear(&varg0);
1401 return hr;
1403 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1405 VariantClear(&varg0);
1406 VariantClear(&varg1);
1407 ERR("MsiSetProperty returned %d\n", ret);
1408 return DISP_E_EXCEPTION;
1411 else return DISP_E_MEMBERNOTFOUND;
1412 break;
1414 case DISPID_SESSION_LANGUAGE:
1415 if (wFlags & DISPATCH_PROPERTYGET) {
1416 langId = MsiGetLanguage(This->msiHandle);
1417 V_VT(pVarResult) = VT_I4;
1418 V_I4(pVarResult) = langId;
1420 else return DISP_E_MEMBERNOTFOUND;
1421 break;
1423 case DISPID_SESSION_MODE:
1424 if (wFlags & DISPATCH_PROPERTYGET) {
1425 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1426 if (FAILED(hr)) return hr;
1427 V_VT(pVarResult) = VT_BOOL;
1428 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0)) ? VARIANT_TRUE : VARIANT_FALSE;
1429 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1430 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1431 if (FAILED(hr)) return hr;
1432 hr = DispGetParam(pDispParams, 1, VT_BOOL, &varg1, puArgErr);
1433 if (FAILED(hr)) return hr;
1434 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1436 ERR("MsiSetMode returned %d\n", ret);
1437 return DISP_E_EXCEPTION;
1440 else return DISP_E_MEMBERNOTFOUND;
1441 break;
1443 case DISPID_SESSION_DATABASE:
1444 if (wFlags & DISPATCH_PROPERTYGET) {
1445 V_VT(pVarResult) = VT_DISPATCH;
1446 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1448 IDispatch *dispatch;
1450 if (SUCCEEDED(hr = create_database(msiHandle, &dispatch)))
1451 V_DISPATCH(pVarResult) = dispatch;
1452 else
1453 ERR("failed to create Database object, hresult %#lx\n", hr);
1455 else
1457 ERR("MsiGetActiveDatabase failed\n");
1458 return DISP_E_EXCEPTION;
1461 else return DISP_E_MEMBERNOTFOUND;
1462 break;
1464 case DISPID_SESSION_DOACTION:
1465 if (wFlags & DISPATCH_METHOD) {
1466 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1467 if (FAILED(hr)) return hr;
1468 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1469 V_VT(pVarResult) = VT_I4;
1470 switch (ret)
1472 case ERROR_FUNCTION_NOT_CALLED:
1473 V_I4(pVarResult) = msiDoActionStatusNoAction;
1474 break;
1475 case ERROR_SUCCESS:
1476 V_I4(pVarResult) = msiDoActionStatusSuccess;
1477 break;
1478 case ERROR_INSTALL_USEREXIT:
1479 V_I4(pVarResult) = msiDoActionStatusUserExit;
1480 break;
1481 case ERROR_INSTALL_FAILURE:
1482 V_I4(pVarResult) = msiDoActionStatusFailure;
1483 break;
1484 case ERROR_INSTALL_SUSPEND:
1485 V_I4(pVarResult) = msiDoActionStatusSuspend;
1486 break;
1487 case ERROR_MORE_DATA:
1488 V_I4(pVarResult) = msiDoActionStatusFinished;
1489 break;
1490 case ERROR_INVALID_HANDLE_STATE:
1491 V_I4(pVarResult) = msiDoActionStatusWrongState;
1492 break;
1493 case ERROR_INVALID_DATA:
1494 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1495 break;
1496 default:
1497 VariantClear(&varg0);
1498 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1499 return DISP_E_EXCEPTION;
1502 else return DISP_E_MEMBERNOTFOUND;
1503 break;
1505 case DISPID_SESSION_EVALUATECONDITION:
1506 if (wFlags & DISPATCH_METHOD) {
1507 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1508 if (FAILED(hr)) return hr;
1509 V_VT(pVarResult) = VT_I4;
1510 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1512 else return DISP_E_MEMBERNOTFOUND;
1513 break;
1515 case DISPID_SESSION_MESSAGE:
1516 if(!(wFlags & DISPATCH_METHOD))
1517 return DISP_E_MEMBERNOTFOUND;
1519 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1520 if (FAILED(hr)) return hr;
1521 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1522 if (FAILED(hr)) return hr;
1524 V_VT(pVarResult) = VT_I4;
1525 V_I4(pVarResult) =
1526 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((struct automation_object *)V_DISPATCH(&varg1))->msiHandle);
1527 break;
1529 case DISPID_SESSION_SETINSTALLLEVEL:
1530 if (wFlags & DISPATCH_METHOD) {
1531 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1532 if (FAILED(hr)) return hr;
1533 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1535 ERR("MsiSetInstallLevel returned %d\n", ret);
1536 return DISP_E_EXCEPTION;
1539 else return DISP_E_MEMBERNOTFOUND;
1540 break;
1542 case DISPID_SESSION_FEATURECURRENTSTATE:
1543 if (wFlags & DISPATCH_PROPERTYGET) {
1544 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1545 if (FAILED(hr)) return hr;
1546 V_VT(pVarResult) = VT_I4;
1547 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1548 V_I4(pVarResult) = iInstalled;
1549 else
1551 ERR("MsiGetFeatureState returned %d\n", ret);
1552 V_I4(pVarResult) = msiInstallStateUnknown;
1555 else return DISP_E_MEMBERNOTFOUND;
1556 break;
1558 case DISPID_SESSION_FEATUREREQUESTSTATE:
1559 if (wFlags & DISPATCH_PROPERTYGET) {
1560 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1561 if (FAILED(hr)) return hr;
1562 V_VT(pVarResult) = VT_I4;
1563 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1564 V_I4(pVarResult) = iAction;
1565 else
1567 ERR("MsiGetFeatureState returned %d\n", ret);
1568 V_I4(pVarResult) = msiInstallStateUnknown;
1570 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1571 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1572 if (FAILED(hr)) return hr;
1573 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1574 if (FAILED(hr)) {
1575 VariantClear(&varg0);
1576 return hr;
1578 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1580 VariantClear(&varg0);
1581 ERR("MsiSetFeatureState returned %d\n", ret);
1582 return DISP_E_EXCEPTION;
1585 else return DISP_E_MEMBERNOTFOUND;
1586 break;
1588 default:
1589 return DISP_E_MEMBERNOTFOUND;
1592 VariantClear(&varg1);
1593 VariantClear(&varg0);
1595 return S_OK;
1598 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1599 * registry value type. Used by Installer::RegistryValue. */
1600 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1602 WCHAR *szString = (WCHAR *)lpData;
1603 LPWSTR szNewString = NULL;
1604 DWORD dwNewSize = 0;
1605 int idx;
1607 switch (dwType)
1609 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1610 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1611 idx = (dwSize/sizeof(WCHAR))-1;
1612 while (idx >= 0 && !szString[idx]) idx--;
1613 for (; idx >= 0; idx--)
1614 if (!szString[idx]) szString[idx] = '\n';
1615 /* fall through */
1616 case REG_SZ:
1617 V_VT(pVarResult) = VT_BSTR;
1618 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1619 break;
1621 case REG_EXPAND_SZ:
1622 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1623 ERR("ExpandEnvironmentStrings returned error %lu\n", GetLastError());
1624 else if (!(szNewString = malloc(dwNewSize * sizeof(WCHAR))))
1625 ERR("Out of memory\n");
1626 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1627 ERR("ExpandEnvironmentStrings returned error %lu\n", GetLastError());
1628 else
1630 V_VT(pVarResult) = VT_BSTR;
1631 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1633 free(szNewString);
1634 break;
1636 case REG_DWORD:
1637 V_VT(pVarResult) = VT_I4;
1638 V_I4(pVarResult) = *((DWORD *)lpData);
1639 break;
1641 case REG_QWORD:
1642 V_VT(pVarResult) = VT_BSTR;
1643 V_BSTR(pVarResult) = SysAllocString(L"(REG_\?\?)"); /* Weird string, don't know why native returns it */
1644 break;
1646 case REG_BINARY:
1647 V_VT(pVarResult) = VT_BSTR;
1648 V_BSTR(pVarResult) = SysAllocString(L"(REG_BINARY)");
1649 break;
1651 case REG_NONE:
1652 V_VT(pVarResult) = VT_EMPTY;
1653 break;
1655 default:
1656 FIXME("Unhandled registry value type %lu\n", dwType);
1660 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1661 DISPPARAMS* pDispParams,
1662 VARIANT* pVarResult,
1663 EXCEPINFO* pExcepInfo,
1664 UINT* puArgErr)
1666 HRESULT hr;
1667 VARIANTARG varg0;
1668 MSIHANDLE hrec;
1670 if (!(wFlags & DISPATCH_METHOD))
1671 return DISP_E_MEMBERNOTFOUND;
1673 VariantInit(&varg0);
1674 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1675 if (FAILED(hr))
1676 return hr;
1678 V_VT(pVarResult) = VT_DISPATCH;
1680 hrec = MsiCreateRecord(V_I4(&varg0));
1681 if (!hrec)
1682 return DISP_E_EXCEPTION;
1684 return create_record(hrec, &V_DISPATCH(pVarResult));
1687 static HRESULT InstallerImpl_OpenPackage(struct automation_object *This,
1688 WORD wFlags,
1689 DISPPARAMS* pDispParams,
1690 VARIANT* pVarResult,
1691 EXCEPINFO* pExcepInfo,
1692 UINT* puArgErr)
1694 UINT ret;
1695 HRESULT hr;
1696 MSIHANDLE hpkg;
1697 IDispatch* dispatch;
1698 VARIANTARG varg0, varg1;
1700 if (!(wFlags & DISPATCH_METHOD))
1701 return DISP_E_MEMBERNOTFOUND;
1703 if (pDispParams->cArgs == 0)
1704 return DISP_E_TYPEMISMATCH;
1706 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1707 return DISP_E_TYPEMISMATCH;
1709 VariantInit(&varg0);
1710 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1711 if (FAILED(hr))
1712 return hr;
1714 VariantInit(&varg1);
1715 if (pDispParams->cArgs == 2)
1717 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1718 if (FAILED(hr))
1719 goto done;
1721 else
1723 V_VT(&varg1) = VT_I4;
1724 V_I4(&varg1) = 0;
1727 V_VT(pVarResult) = VT_DISPATCH;
1729 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1730 if (ret != ERROR_SUCCESS)
1732 hr = DISP_E_EXCEPTION;
1733 goto done;
1736 hr = create_session(hpkg, &This->IDispatch_iface, &dispatch);
1737 if (SUCCEEDED(hr))
1738 V_DISPATCH(pVarResult) = dispatch;
1740 done:
1741 VariantClear(&varg0);
1742 VariantClear(&varg1);
1743 return hr;
1746 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1747 DISPPARAMS* pDispParams,
1748 VARIANT* pVarResult,
1749 EXCEPINFO* pExcepInfo,
1750 UINT* puArgErr)
1752 HRESULT hr;
1753 VARIANTARG varg0;
1755 if (!(wFlags & DISPATCH_METHOD))
1756 return DISP_E_MEMBERNOTFOUND;
1758 VariantInit(&varg0);
1759 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1760 if (FAILED(hr))
1761 return hr;
1763 FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1765 VariantInit(pVarResult);
1767 VariantClear(&varg0);
1768 return S_OK;
1771 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1772 DISPPARAMS* pDispParams,
1773 VARIANT* pVarResult,
1774 EXCEPINFO* pExcepInfo,
1775 UINT* puArgErr)
1777 UINT ret;
1778 HRESULT hr;
1779 MSIHANDLE hdb;
1780 IDispatch* dispatch;
1781 VARIANTARG varg0, varg1;
1783 if (!(wFlags & DISPATCH_METHOD))
1784 return DISP_E_MEMBERNOTFOUND;
1786 VariantInit(&varg0);
1787 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1788 if (FAILED(hr))
1789 return hr;
1791 VariantInit(&varg1);
1792 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1793 if (FAILED(hr))
1794 goto done;
1796 V_VT(pVarResult) = VT_DISPATCH;
1798 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1799 if (ret != ERROR_SUCCESS)
1801 hr = DISP_E_EXCEPTION;
1802 goto done;
1805 hr = create_database(hdb, &dispatch);
1806 if (SUCCEEDED(hr))
1807 V_DISPATCH(pVarResult) = dispatch;
1809 done:
1810 VariantClear(&varg0);
1811 VariantClear(&varg1);
1812 return hr;
1815 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1816 DISPPARAMS* pDispParams,
1817 VARIANT* pVarResult,
1818 EXCEPINFO* pExcepInfo,
1819 UINT* puArgErr)
1821 UINT ret;
1822 HRESULT hr;
1823 MSIHANDLE hsuminfo;
1824 IDispatch *dispatch;
1825 VARIANTARG varg0, varg1;
1827 if (!(wFlags & DISPATCH_PROPERTYGET))
1828 return DISP_E_MEMBERNOTFOUND;
1830 VariantInit(&varg1);
1831 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1832 if (FAILED(hr))
1833 return hr;
1835 VariantInit(&varg0);
1836 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1837 if (FAILED(hr))
1838 return hr;
1840 ret = MsiGetSummaryInformationW(0, V_BSTR(&varg0), V_I4(&varg1), &hsuminfo);
1841 VariantClear(&varg0);
1842 if (ret != ERROR_SUCCESS)
1843 return DISP_E_EXCEPTION;
1845 hr = create_summaryinfo(hsuminfo, &dispatch);
1846 if (FAILED(hr))
1847 return hr;
1849 V_VT(pVarResult) = VT_DISPATCH;
1850 V_DISPATCH(pVarResult) = dispatch;
1851 return S_OK;
1854 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1855 DISPPARAMS* pDispParams,
1856 VARIANT* pVarResult,
1857 EXCEPINFO* pExcepInfo,
1858 UINT* puArgErr)
1860 HRESULT hr;
1861 VARIANTARG varg0;
1862 INSTALLUILEVEL ui;
1864 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1865 return DISP_E_MEMBERNOTFOUND;
1867 if (wFlags & DISPATCH_PROPERTYPUT)
1869 VariantInit(&varg0);
1870 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1871 if (FAILED(hr))
1872 return hr;
1874 ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1875 if (ui == INSTALLUILEVEL_NOCHANGE)
1876 return DISP_E_EXCEPTION;
1878 else if (wFlags & DISPATCH_PROPERTYGET)
1880 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1881 if (ui == INSTALLUILEVEL_NOCHANGE)
1882 return DISP_E_EXCEPTION;
1884 V_VT(pVarResult) = VT_I4;
1885 V_I4(pVarResult) = ui;
1888 return S_OK;
1891 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1892 DISPPARAMS* pDispParams,
1893 VARIANT* pVarResult,
1894 EXCEPINFO* pExcepInfo,
1895 UINT* puArgErr)
1897 if (!(wFlags & DISPATCH_METHOD))
1898 return DISP_E_MEMBERNOTFOUND;
1900 FIXME("\n");
1902 VariantInit(pVarResult);
1903 return S_OK;
1906 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1907 DISPPARAMS* pDispParams,
1908 VARIANT* pVarResult,
1909 EXCEPINFO* pExcepInfo,
1910 UINT* puArgErr)
1912 UINT ret;
1913 HRESULT hr;
1914 VARIANTARG varg0, varg1;
1916 if (!(wFlags & DISPATCH_METHOD))
1917 return DISP_E_MEMBERNOTFOUND;
1919 VariantInit(&varg0);
1920 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1921 if (FAILED(hr))
1922 return hr;
1924 VariantInit(&varg1);
1925 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1926 if (FAILED(hr))
1927 goto done;
1929 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1930 if (ret != ERROR_SUCCESS)
1932 hr = DISP_E_EXCEPTION;
1933 goto done;
1936 done:
1937 VariantClear(&varg0);
1938 VariantClear(&varg1);
1939 return hr;
1942 static HRESULT InstallerImpl_Version(WORD wFlags,
1943 VARIANT* pVarResult,
1944 EXCEPINFO* pExcepInfo,
1945 UINT* puArgErr)
1947 HRESULT hr;
1948 DLLVERSIONINFO verinfo;
1949 WCHAR version[MAX_PATH];
1951 if (!(wFlags & DISPATCH_PROPERTYGET))
1952 return DISP_E_MEMBERNOTFOUND;
1954 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1955 hr = DllGetVersion(&verinfo);
1956 if (FAILED(hr))
1957 return hr;
1959 swprintf(version, ARRAY_SIZE(version), L"%d.%d.%d.%d", verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1960 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1962 V_VT(pVarResult) = VT_BSTR;
1963 V_BSTR(pVarResult) = SysAllocString(version);
1964 return S_OK;
1967 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1968 DISPPARAMS* pDispParams,
1969 VARIANT* pVarResult,
1970 EXCEPINFO* pExcepInfo,
1971 UINT* puArgErr)
1973 if (!(wFlags & DISPATCH_METHOD))
1974 return DISP_E_MEMBERNOTFOUND;
1976 FIXME("\n");
1978 VariantInit(pVarResult);
1979 return S_OK;
1982 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1983 DISPPARAMS* pDispParams,
1984 VARIANT* pVarResult,
1985 EXCEPINFO* pExcepInfo,
1986 UINT* puArgErr)
1988 UINT ret;
1989 HKEY hkey = NULL;
1990 HRESULT hr;
1991 UINT posValue;
1992 DWORD type, size;
1993 LPWSTR szString = NULL;
1994 VARIANTARG varg0, varg1, varg2;
1996 if (!(wFlags & DISPATCH_METHOD))
1997 return DISP_E_MEMBERNOTFOUND;
1999 VariantInit(&varg0);
2000 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
2001 if (FAILED(hr))
2002 return hr;
2004 VariantInit(&varg1);
2005 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2006 if (FAILED(hr))
2007 goto done;
2009 /* Save valuePos so we can save puArgErr if we are unable to do our type
2010 * conversions.
2012 posValue = 2;
2013 VariantInit(&varg2);
2014 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
2015 if (FAILED(hr))
2016 goto done;
2018 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
2019 V_I4(&varg0) <= REG_INDEX_DYN_DATA)
2021 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
2024 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
2026 /* Only VT_EMPTY case can do anything if the key doesn't exist. */
2027 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
2029 hr = DISP_E_BADINDEX;
2030 goto done;
2033 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
2034 switch (V_VT(&varg2))
2036 /* Return VT_BOOL clarifying whether registry key exists or not. */
2037 case VT_EMPTY:
2038 V_VT(pVarResult) = VT_BOOL;
2039 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS) ? VARIANT_TRUE : VARIANT_FALSE;
2040 break;
2042 /* Return the value of specified key if it exists. */
2043 case VT_BSTR:
2044 ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
2045 NULL, NULL, NULL, &size);
2046 if (ret != ERROR_SUCCESS)
2048 hr = DISP_E_BADINDEX;
2049 goto done;
2052 szString = malloc(size);
2053 if (!szString)
2055 hr = E_OUTOFMEMORY;
2056 goto done;
2059 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
2060 &type, (LPBYTE)szString, &size);
2061 if (ret != ERROR_SUCCESS)
2063 free(szString);
2064 hr = DISP_E_BADINDEX;
2065 goto done;
2068 variant_from_registry_value(pVarResult, type,
2069 (LPBYTE)szString, size);
2070 free(szString);
2071 break;
2073 /* Try to make it into VT_I4, can use VariantChangeType for this. */
2074 default:
2075 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
2076 if (FAILED(hr))
2078 if (hr == DISP_E_TYPEMISMATCH)
2079 *puArgErr = posValue;
2081 goto done;
2084 /* Retrieve class name or maximum value name or subkey name size. */
2085 if (!V_I4(&varg2))
2086 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
2087 NULL, NULL, NULL, NULL, NULL, NULL);
2088 else if (V_I4(&varg2) > 0)
2089 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
2090 NULL, NULL, &size, NULL, NULL, NULL);
2091 else /* V_I4(&varg2) < 0 */
2092 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
2093 NULL, NULL, NULL, NULL, NULL, NULL);
2095 if (ret != ERROR_SUCCESS)
2096 goto done;
2098 szString = malloc(++size * sizeof(WCHAR));
2099 if (!szString)
2101 hr = E_OUTOFMEMORY;
2102 goto done;
2105 if (!V_I4(&varg2))
2106 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
2107 NULL, NULL, NULL, NULL, NULL, NULL);
2108 else if (V_I4(&varg2) > 0)
2109 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
2110 &size, 0, 0, NULL, NULL);
2111 else /* V_I4(&varg2) < 0 */
2112 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
2114 if (ret == ERROR_SUCCESS)
2116 V_VT(pVarResult) = VT_BSTR;
2117 V_BSTR(pVarResult) = SysAllocString(szString);
2120 free(szString);
2123 done:
2124 VariantClear(&varg0);
2125 VariantClear(&varg1);
2126 VariantClear(&varg2);
2127 RegCloseKey(hkey);
2128 return hr;
2131 static HRESULT InstallerImpl_Environment(WORD wFlags,
2132 DISPPARAMS* pDispParams,
2133 VARIANT* pVarResult,
2134 EXCEPINFO* pExcepInfo,
2135 UINT* puArgErr)
2137 if (!(wFlags & DISPATCH_METHOD))
2138 return DISP_E_MEMBERNOTFOUND;
2140 FIXME("\n");
2142 VariantInit(pVarResult);
2143 return S_OK;
2146 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2147 DISPPARAMS* pDispParams,
2148 VARIANT* pVarResult,
2149 EXCEPINFO* pExcepInfo,
2150 UINT* puArgErr)
2152 if (!(wFlags & DISPATCH_METHOD))
2153 return DISP_E_MEMBERNOTFOUND;
2155 FIXME("\n");
2157 VariantInit(pVarResult);
2158 return S_OK;
2161 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2162 DISPPARAMS* pDispParams,
2163 VARIANT* pVarResult,
2164 EXCEPINFO* pExcepInfo,
2165 UINT* puArgErr)
2167 if (!(wFlags & DISPATCH_METHOD))
2168 return DISP_E_MEMBERNOTFOUND;
2170 FIXME("\n");
2172 VariantInit(pVarResult);
2173 return S_OK;
2176 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2177 DISPPARAMS* pDispParams,
2178 VARIANT* pVarResult,
2179 EXCEPINFO* pExcepInfo,
2180 UINT* puArgErr)
2182 if (!(wFlags & DISPATCH_METHOD))
2183 return DISP_E_MEMBERNOTFOUND;
2185 FIXME("\n");
2187 VariantInit(pVarResult);
2188 return S_OK;
2191 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2192 DISPPARAMS* pDispParams,
2193 VARIANT* pVarResult,
2194 EXCEPINFO* pExcepInfo,
2195 UINT* puArgErr)
2197 HRESULT hr;
2198 VARIANTARG varg0;
2200 if (!(wFlags & DISPATCH_PROPERTYGET))
2201 return DISP_E_MEMBERNOTFOUND;
2203 VariantInit(&varg0);
2204 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2205 if (FAILED(hr))
2206 return hr;
2208 V_VT(pVarResult) = VT_I4;
2209 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2211 VariantClear(&varg0);
2212 return S_OK;
2215 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2216 DISPPARAMS* pDispParams,
2217 VARIANT* pVarResult,
2218 EXCEPINFO* pExcepInfo,
2219 UINT* puArgErr)
2221 UINT ret;
2222 HRESULT hr;
2223 DWORD size;
2224 LPWSTR str = NULL;
2225 VARIANTARG varg0, varg1;
2227 if (!(wFlags & DISPATCH_PROPERTYGET))
2228 return DISP_E_MEMBERNOTFOUND;
2230 VariantInit(&varg0);
2231 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2232 if (FAILED(hr))
2233 return hr;
2235 VariantInit(&varg1);
2236 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2237 if (FAILED(hr))
2238 goto done;
2240 V_VT(pVarResult) = VT_BSTR;
2241 V_BSTR(pVarResult) = NULL;
2243 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2244 if (ret != ERROR_SUCCESS)
2246 hr = DISP_E_EXCEPTION;
2247 goto done;
2250 str = malloc(++size * sizeof(WCHAR));
2251 if (!str)
2253 hr = E_OUTOFMEMORY;
2254 goto done;
2257 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2258 if (ret != ERROR_SUCCESS)
2260 hr = DISP_E_EXCEPTION;
2261 goto done;
2264 V_BSTR(pVarResult) = SysAllocString(str);
2265 hr = S_OK;
2267 done:
2268 free(str);
2269 VariantClear(&varg0);
2270 VariantClear(&varg1);
2271 return hr;
2274 static HRESULT InstallerImpl_Products(WORD flags,
2275 DISPPARAMS* pDispParams,
2276 VARIANT* result,
2277 EXCEPINFO* pExcepInfo,
2278 UINT* puArgErr)
2280 IDispatch *dispatch;
2281 HRESULT hr;
2283 if (!(flags & DISPATCH_PROPERTYGET))
2284 return DISP_E_MEMBERNOTFOUND;
2286 hr = create_list(NULL, &dispatch);
2287 if (FAILED(hr))
2288 return hr;
2290 V_VT(result) = VT_DISPATCH;
2291 V_DISPATCH(result) = dispatch;
2293 return hr;
2296 static HRESULT InstallerImpl_RelatedProducts(WORD flags,
2297 DISPPARAMS* pDispParams,
2298 VARIANT* result,
2299 EXCEPINFO* pExcepInfo,
2300 UINT* puArgErr)
2302 IDispatch* dispatch;
2303 VARIANTARG related;
2304 HRESULT hr;
2306 if (!(flags & DISPATCH_PROPERTYGET))
2307 return DISP_E_MEMBERNOTFOUND;
2309 VariantInit(&related);
2310 hr = DispGetParam(pDispParams, 0, VT_BSTR, &related, puArgErr);
2311 if (FAILED(hr))
2312 return hr;
2314 hr = create_list(V_BSTR(&related), &dispatch);
2315 VariantClear(&related);
2317 V_VT(result) = VT_DISPATCH;
2318 V_DISPATCH(result) = dispatch;
2320 return hr;
2323 static HRESULT installer_invoke(
2324 struct automation_object *This,
2325 DISPID dispIdMember,
2326 REFIID riid,
2327 LCID lcid,
2328 WORD wFlags,
2329 DISPPARAMS* pDispParams,
2330 VARIANT* pVarResult,
2331 EXCEPINFO* pExcepInfo,
2332 UINT* puArgErr)
2334 switch (dispIdMember)
2336 case DISPID_INSTALLER_CREATERECORD:
2337 return InstallerImpl_CreateRecord(wFlags, pDispParams,
2338 pVarResult, pExcepInfo, puArgErr);
2340 case DISPID_INSTALLER_OPENPACKAGE:
2341 return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2342 pVarResult, pExcepInfo, puArgErr);
2344 case DISPID_INSTALLER_OPENPRODUCT:
2345 return InstallerImpl_OpenProduct(wFlags, pDispParams,
2346 pVarResult, pExcepInfo, puArgErr);
2348 case DISPID_INSTALLER_OPENDATABASE:
2349 return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2350 pVarResult, pExcepInfo, puArgErr);
2352 case DISPID_INSTALLER_SUMMARYINFORMATION:
2353 return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2354 pVarResult, pExcepInfo,
2355 puArgErr);
2357 case DISPID_INSTALLER_UILEVEL:
2358 return InstallerImpl_UILevel(wFlags, pDispParams,
2359 pVarResult, pExcepInfo, puArgErr);
2361 case DISPID_INSTALLER_ENABLELOG:
2362 return InstallerImpl_EnableLog(wFlags, pDispParams,
2363 pVarResult, pExcepInfo, puArgErr);
2365 case DISPID_INSTALLER_INSTALLPRODUCT:
2366 return InstallerImpl_InstallProduct(wFlags, pDispParams,
2367 pVarResult, pExcepInfo,
2368 puArgErr);
2370 case DISPID_INSTALLER_VERSION:
2371 return InstallerImpl_Version(wFlags, pVarResult,
2372 pExcepInfo, puArgErr);
2374 case DISPID_INSTALLER_LASTERRORRECORD:
2375 return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2376 pVarResult, pExcepInfo,
2377 puArgErr);
2379 case DISPID_INSTALLER_REGISTRYVALUE:
2380 return InstallerImpl_RegistryValue(wFlags, pDispParams,
2381 pVarResult, pExcepInfo,
2382 puArgErr);
2384 case DISPID_INSTALLER_ENVIRONMENT:
2385 return InstallerImpl_Environment(wFlags, pDispParams,
2386 pVarResult, pExcepInfo, puArgErr);
2388 case DISPID_INSTALLER_FILEATTRIBUTES:
2389 return InstallerImpl_FileAttributes(wFlags, pDispParams,
2390 pVarResult, pExcepInfo,
2391 puArgErr);
2393 case DISPID_INSTALLER_FILESIZE:
2394 return InstallerImpl_FileSize(wFlags, pDispParams,
2395 pVarResult, pExcepInfo, puArgErr);
2397 case DISPID_INSTALLER_FILEVERSION:
2398 return InstallerImpl_FileVersion(wFlags, pDispParams,
2399 pVarResult, pExcepInfo, puArgErr);
2401 case DISPID_INSTALLER_PRODUCTSTATE:
2402 return InstallerImpl_ProductState(wFlags, pDispParams,
2403 pVarResult, pExcepInfo, puArgErr);
2405 case DISPID_INSTALLER_PRODUCTINFO:
2406 return InstallerImpl_ProductInfo(wFlags, pDispParams,
2407 pVarResult, pExcepInfo, puArgErr);
2409 case DISPID_INSTALLER_PRODUCTS:
2410 return InstallerImpl_Products(wFlags, pDispParams,
2411 pVarResult, pExcepInfo, puArgErr);
2413 case DISPID_INSTALLER_RELATEDPRODUCTS:
2414 return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2415 pVarResult, pExcepInfo,
2416 puArgErr);
2418 default:
2419 return DISP_E_MEMBERNOTFOUND;
2423 HRESULT create_msiserver(IUnknown *outer, void **ppObj)
2425 struct automation_object *installer;
2427 TRACE("(%p %p)\n", outer, ppObj);
2429 if (outer)
2430 return CLASS_E_NOAGGREGATION;
2432 installer = malloc(sizeof(*installer));
2433 if (!installer) return E_OUTOFMEMORY;
2435 init_automation_object(installer, 0, Installer_tid);
2437 *ppObj = &installer->IDispatch_iface;
2439 return S_OK;
2442 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp)
2444 struct session_object *session;
2446 session = malloc(sizeof(*session));
2447 if (!session) return E_OUTOFMEMORY;
2449 init_automation_object(&session->autoobj, msiHandle, Session_tid);
2451 session->installer = installer;
2452 *disp = &session->autoobj.IDispatch_iface;
2454 return S_OK;
2457 static HRESULT create_database(MSIHANDLE msiHandle, IDispatch **dispatch)
2459 struct automation_object *database;
2461 TRACE("%lu %p\n", msiHandle, dispatch);
2463 database = malloc(sizeof(*database));
2464 if (!database) return E_OUTOFMEMORY;
2466 init_automation_object(database, msiHandle, Database_tid);
2468 *dispatch = &database->IDispatch_iface;
2470 return S_OK;
2473 static HRESULT create_view(MSIHANDLE msiHandle, IDispatch **dispatch)
2475 struct automation_object *view;
2477 TRACE("%lu %p\n", msiHandle, dispatch);
2479 view = malloc(sizeof(*view));
2480 if (!view) return E_OUTOFMEMORY;
2482 init_automation_object(view, msiHandle, View_tid);
2484 *dispatch = &view->IDispatch_iface;
2486 return S_OK;
2489 static HRESULT create_summaryinfo(MSIHANDLE msiHandle, IDispatch **disp)
2491 struct automation_object *info;
2493 info = malloc(sizeof(*info));
2494 if (!info) return E_OUTOFMEMORY;
2496 init_automation_object(info, msiHandle, SummaryInfo_tid);
2498 *disp = &info->IDispatch_iface;
2500 return S_OK;