msi: Add a helper to create database object.
[wine/multimedia.git] / dlls / msi / automation.c
blob2e08a8ce8dbfcb4455606bd69bb966d24cb2a4db
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
46 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
47 * called from AutomationObject::Invoke, and pass this function to create_automation_object.
50 typedef struct AutomationObject AutomationObject;
52 typedef HRESULT (*autoInvokeFunc)(AutomationObject* This,
53 DISPID dispIdMember, REFIID riid, LCID lcid, WORD flags, DISPPARAMS* pDispParams,
54 VARIANT* result, EXCEPINFO* ei, UINT* arg_err);
56 typedef void (*autoFreeFunc)(AutomationObject* This);
58 struct AutomationObject {
59 IDispatch IDispatch_iface;
60 IProvideMultipleClassInfo IProvideMultipleClassInfo_iface;
61 LONG ref;
63 /* Clsid for this class and it's appropriate ITypeInfo object */
64 LPCLSID clsid;
65 ITypeInfo *iTypeInfo;
67 /* The MSI handle of the current object */
68 MSIHANDLE msiHandle;
70 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
71 autoInvokeFunc funcInvoke;
72 /* A function that is called from AutomationObject::Release when the object is being freed to free any private
73 * data structures (or NULL) */
74 autoFreeFunc funcFree;
77 static HRESULT create_list_enumerator(IUnknown*, void**, AutomationObject*, ULONG);
80 * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
83 typedef struct {
84 IEnumVARIANT IEnumVARIANT_iface;
85 LONG ref;
87 /* Current position and pointer to AutomationObject that stores actual data */
88 ULONG ulPos;
89 AutomationObject *pObj;
90 } ListEnumerator;
93 * Structures for additional data required by specific automation objects
96 typedef struct {
97 ULONG ulCount;
98 VARIANT *pVars;
99 } ListData;
101 typedef struct {
102 AutomationObject autoobj;
103 IDispatch *installer;
104 } SessionObject;
106 static inline AutomationObject *impl_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
108 return CONTAINING_RECORD(iface, AutomationObject, IProvideMultipleClassInfo_iface);
111 static inline AutomationObject *impl_from_IDispatch( IDispatch *iface )
113 return CONTAINING_RECORD(iface, AutomationObject, IDispatch_iface);
116 /* Load type info so we don't have to process GetIDsOfNames */
117 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
119 static const WCHAR msiserverW[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b',0};
120 ITypeInfo *ti = NULL;
121 ITypeLib *lib = NULL;
122 HRESULT hr;
124 TRACE("(%p)->(%s, %d)\n", iface, debugstr_guid(clsid), lcid);
126 /* Load registered type library */
127 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &lib);
128 if (FAILED(hr)) {
129 hr = LoadTypeLib(msiserverW, &lib);
130 if (FAILED(hr)) {
131 ERR("Could not load msiserver.tlb\n");
132 return hr;
136 /* Get type information for object */
137 hr = ITypeLib_GetTypeInfoOfGuid(lib, clsid, &ti);
138 ITypeLib_Release(lib);
139 if (FAILED(hr)) {
140 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
141 return hr;
143 *pptinfo = ti;
144 return S_OK;
147 /* Macro to get pointer to private object data */
148 static inline void *private_data( AutomationObject *This )
150 return This + 1;
154 * AutomationObject methods
157 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
159 AutomationObject *This = impl_from_IDispatch(iface);
161 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
163 if (ppvObject == NULL)
164 return E_INVALIDARG;
166 *ppvObject = 0;
168 if (IsEqualGUID(riid, &IID_IUnknown) ||
169 IsEqualGUID(riid, &IID_IDispatch) ||
170 IsEqualGUID(riid, This->clsid))
171 *ppvObject = &This->IDispatch_iface;
172 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
173 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
174 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
175 *ppvObject = &This->IProvideMultipleClassInfo_iface;
176 else
178 TRACE("() : asking for unsupported interface %s\n", debugstr_guid(riid));
179 return E_NOINTERFACE;
182 IDispatch_AddRef(iface);
184 return S_OK;
187 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
189 AutomationObject *This = impl_from_IDispatch(iface);
191 TRACE("(%p/%p)\n", iface, This);
193 return InterlockedIncrement(&This->ref);
196 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
198 AutomationObject *This = impl_from_IDispatch(iface);
199 ULONG ref = InterlockedDecrement(&This->ref);
201 TRACE("(%p/%p)\n", iface, This);
203 if (!ref)
205 if (This->funcFree) This->funcFree(This);
206 ITypeInfo_Release(This->iTypeInfo);
207 MsiCloseHandle(This->msiHandle);
208 msi_free(This);
211 return ref;
214 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
215 IDispatch* iface,
216 UINT* pctinfo)
218 AutomationObject *This = impl_from_IDispatch(iface);
220 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
221 *pctinfo = 1;
222 return S_OK;
225 static HRESULT WINAPI AutomationObject_GetTypeInfo(
226 IDispatch* iface,
227 UINT iTInfo,
228 LCID lcid,
229 ITypeInfo** ppTInfo)
231 AutomationObject *This = impl_from_IDispatch(iface);
232 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
234 ITypeInfo_AddRef(This->iTypeInfo);
235 *ppTInfo = This->iTypeInfo;
236 return S_OK;
239 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
240 IDispatch* iface,
241 REFIID riid,
242 LPOLESTR* rgszNames,
243 UINT cNames,
244 LCID lcid,
245 DISPID* rgDispId)
247 AutomationObject *This = impl_from_IDispatch(iface);
248 HRESULT hr;
249 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
251 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
252 hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
253 if (hr == DISP_E_UNKNOWNNAME)
255 UINT idx;
256 for (idx=0; idx<cNames; idx++)
258 if (rgDispId[idx] == DISPID_UNKNOWN)
259 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
262 return hr;
265 /* Maximum number of allowed function parameters+1 */
266 #define MAX_FUNC_PARAMS 20
268 /* Some error checking is done here to simplify individual object function invocation */
269 static HRESULT WINAPI AutomationObject_Invoke(
270 IDispatch* iface,
271 DISPID dispIdMember,
272 REFIID riid,
273 LCID lcid,
274 WORD wFlags,
275 DISPPARAMS* pDispParams,
276 VARIANT* pVarResult,
277 EXCEPINFO* pExcepInfo,
278 UINT* puArgErr)
280 AutomationObject *This = impl_from_IDispatch(iface);
281 HRESULT hr;
282 unsigned int uArgErr;
283 VARIANT varResultDummy;
284 BSTR bstrName = NULL;
286 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
288 if (!IsEqualIID(riid, &IID_NULL))
290 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
291 return DISP_E_UNKNOWNNAME;
294 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
296 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
297 return DISP_E_PARAMNOTOPTIONAL;
300 /* This simplifies our individual object invocation functions */
301 if (puArgErr == NULL) puArgErr = &uArgErr;
302 if (pVarResult == NULL) pVarResult = &varResultDummy;
304 /* Assume return type is void unless determined otherwise */
305 VariantInit(pVarResult);
307 /* If we are tracing, we want to see the name of the member we are invoking */
308 if (TRACE_ON(msi))
310 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
311 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
314 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
316 if (hr == DISP_E_MEMBERNOTFOUND) {
317 if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
318 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
320 else if (pExcepInfo &&
321 (hr == DISP_E_PARAMNOTFOUND ||
322 hr == DISP_E_EXCEPTION)) {
323 static const WCHAR szComma[] = { ',',0 };
324 static const WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
325 WCHAR szExceptionDescription[MAX_PATH];
326 BSTR bstrParamNames[MAX_FUNC_PARAMS];
327 unsigned namesNo, i;
328 BOOL bFirst = TRUE;
330 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
331 MAX_FUNC_PARAMS, &namesNo)))
333 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
335 else
337 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
338 for (i=0; i<namesNo; i++)
340 if (bFirst) bFirst = FALSE;
341 else {
342 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
344 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
345 SysFreeString(bstrParamNames[i]);
348 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
349 pExcepInfo->wCode = 1000;
350 pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
351 pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
352 hr = DISP_E_EXCEPTION;
356 /* Make sure we free the return variant if it is our dummy variant */
357 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
359 /* Free function name if we retrieved it */
360 SysFreeString(bstrName);
362 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
364 return hr;
367 static const struct IDispatchVtbl AutomationObjectVtbl =
369 AutomationObject_QueryInterface,
370 AutomationObject_AddRef,
371 AutomationObject_Release,
372 AutomationObject_GetTypeInfoCount,
373 AutomationObject_GetTypeInfo,
374 AutomationObject_GetIDsOfNames,
375 AutomationObject_Invoke
379 * IProvideMultipleClassInfo methods
382 static HRESULT WINAPI ProvideMultipleClassInfo_QueryInterface(
383 IProvideMultipleClassInfo* iface,
384 REFIID riid,
385 VOID** ppvoid)
387 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
388 return IDispatch_QueryInterface(&This->IDispatch_iface, riid, ppvoid);
391 static ULONG WINAPI ProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
393 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
394 return IDispatch_AddRef(&This->IDispatch_iface);
397 static ULONG WINAPI ProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
399 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
400 return IDispatch_Release(&This->IDispatch_iface);
403 static HRESULT WINAPI ProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
405 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
406 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
407 return load_type_info(&This->IDispatch_iface, ppTI, This->clsid, 0);
410 static HRESULT WINAPI ProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
412 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
413 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
415 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
416 return E_INVALIDARG;
417 else {
418 *pGUID = *This->clsid;
419 return S_OK;
423 static HRESULT WINAPI ProvideMultipleClassInfo_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
425 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
427 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
428 *pcti = 1;
429 return S_OK;
432 static HRESULT WINAPI ProvideMultipleClassInfo_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
433 ULONG iti,
434 DWORD dwFlags,
435 ITypeInfo** pptiCoClass,
436 DWORD* pdwTIFlags,
437 ULONG* pcdispidReserved,
438 IID* piidPrimary,
439 IID* piidSource)
441 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
443 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
445 if (iti != 0)
446 return E_INVALIDARG;
448 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
449 load_type_info(&This->IDispatch_iface, pptiCoClass, This->clsid, 0);
451 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
453 *pdwTIFlags = 0;
454 *pcdispidReserved = 0;
457 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
458 *piidPrimary = *This->clsid;
461 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
462 *piidSource = *This->clsid;
465 return S_OK;
468 static const IProvideMultipleClassInfoVtbl ProvideMultipleClassInfoVtbl =
470 ProvideMultipleClassInfo_QueryInterface,
471 ProvideMultipleClassInfo_AddRef,
472 ProvideMultipleClassInfo_Release,
473 ProvideMultipleClassInfo_GetClassInfo,
474 ProvideMultipleClassInfo_GetGUID,
475 ProvideMultipleClassInfo_GetMultiTypeInfoCount,
476 ProvideMultipleClassInfo_GetInfoOfIndex
479 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
480 * with the appropriate clsid and invocation function. */
481 static HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, void **ppObj, REFIID clsid,
482 autoInvokeFunc invokeFunc, autoFreeFunc freeFunc, SIZE_T sizetPrivateData)
484 AutomationObject *object;
485 HRESULT hr;
487 TRACE("(%d,%p,%p,%s,%p,%p,%ld)\n", msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), invokeFunc, freeFunc, sizetPrivateData);
489 if( pUnkOuter )
490 return CLASS_E_NOAGGREGATION;
492 object = msi_alloc_zero( sizeof(AutomationObject) + sizetPrivateData );
494 object->IDispatch_iface.lpVtbl = &AutomationObjectVtbl;
495 object->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl;
496 object->ref = 1;
498 object->msiHandle = msiHandle;
499 object->clsid = (LPCLSID)clsid;
500 object->funcInvoke = invokeFunc;
501 object->funcFree = freeFunc;
503 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
504 object->iTypeInfo = NULL;
505 hr = load_type_info(&object->IDispatch_iface, &object->iTypeInfo, clsid, 0x0);
506 if (FAILED(hr)) {
507 msi_free( object );
508 return hr;
511 *ppObj = object;
513 return S_OK;
516 static HRESULT init_automation_object(AutomationObject *This, MSIHANDLE msiHandle, REFIID clsid,
517 autoInvokeFunc invokeFunc, autoFreeFunc freeFunc)
519 TRACE("(%p, %d, %s, %p, %p)\n", This, msiHandle, debugstr_guid(clsid), invokeFunc, freeFunc);
521 This->IDispatch_iface.lpVtbl = &AutomationObjectVtbl;
522 This->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl;
523 This->ref = 1;
525 This->msiHandle = msiHandle;
526 This->clsid = (LPCLSID)clsid;
527 This->funcInvoke = invokeFunc;
528 This->funcFree = freeFunc;
530 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
531 This->iTypeInfo = NULL;
532 return load_type_info(&This->IDispatch_iface, &This->iTypeInfo, clsid, 0);
536 * ListEnumerator methods
539 static inline ListEnumerator *impl_from_IEnumVARIANT(IEnumVARIANT* iface)
541 return CONTAINING_RECORD(iface, ListEnumerator, IEnumVARIANT_iface);
544 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid,
545 void** ppvObject)
547 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
549 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
551 if (ppvObject == NULL)
552 return E_INVALIDARG;
554 *ppvObject = 0;
556 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT))
557 *ppvObject = This;
558 else
560 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
561 return E_NOINTERFACE;
564 IClassFactory_AddRef(iface);
565 return S_OK;
568 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
570 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
572 TRACE("(%p/%p)\n", iface, This);
574 return InterlockedIncrement(&This->ref);
577 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
579 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
580 ULONG ref = InterlockedDecrement(&This->ref);
582 TRACE("(%p/%p)\n", iface, This);
584 if (!ref)
586 if (This->pObj) IDispatch_Release(&This->pObj->IDispatch_iface);
587 msi_free(This);
590 return ref;
593 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar,
594 ULONG* pCeltFetched)
596 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
597 ListData *data = private_data(This->pObj);
598 ULONG idx, local;
600 TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched);
602 if (pCeltFetched != NULL)
603 *pCeltFetched = 0;
605 if (rgVar == NULL)
606 return S_FALSE;
608 for (local = 0; local < celt; local++)
609 VariantInit(&rgVar[local]);
611 for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++)
612 VariantCopy(&rgVar[local], &data->pVars[idx]);
614 if (pCeltFetched != NULL)
615 *pCeltFetched = local;
616 This->ulPos = idx;
618 return (local < celt) ? S_FALSE : S_OK;
621 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
623 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
624 ListData *data = private_data(This->pObj);
626 TRACE("(%p,%uld)\n", iface, celt);
628 This->ulPos += celt;
629 if (This->ulPos >= data->ulCount)
631 This->ulPos = data->ulCount;
632 return S_FALSE;
634 return S_OK;
637 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
639 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
641 TRACE("(%p)\n", iface);
643 This->ulPos = 0;
644 return S_OK;
647 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
649 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
650 HRESULT hr;
652 TRACE("(%p,%p)\n", iface, ppEnum);
654 if (ppEnum == NULL)
655 return S_FALSE;
657 *ppEnum = NULL;
658 hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0);
659 if (FAILED(hr))
661 if (*ppEnum)
662 IUnknown_Release(*ppEnum);
663 return hr;
666 return S_OK;
669 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
671 ListEnumerator_QueryInterface,
672 ListEnumerator_AddRef,
673 ListEnumerator_Release,
674 ListEnumerator_Next,
675 ListEnumerator_Skip,
676 ListEnumerator_Reset,
677 ListEnumerator_Clone
680 /* Create a list enumerator, placing the result in the pointer ppObj. */
681 static HRESULT create_list_enumerator(IUnknown *outer, void **ppObj, AutomationObject *aut_obj, ULONG pos)
683 ListEnumerator *object;
685 TRACE("(%p, %p, %p, %uld)\n", outer, ppObj, aut_obj, pos);
687 if( outer )
688 return CLASS_E_NOAGGREGATION;
690 object = msi_alloc( sizeof(ListEnumerator) );
692 /* Set all the VTable references */
693 object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
694 object->ref = 1;
696 /* Store data that was passed */
697 object->ulPos = pos;
698 object->pObj = aut_obj;
699 if (aut_obj) IDispatch_AddRef(&aut_obj->IDispatch_iface);
701 *ppObj = object;
702 return S_OK;
706 * Individual Object Invocation Functions
709 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
710 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
711 using DispGetParam/VariantChangeType. */
712 static HRESULT DispGetParam_CopyOnly(
713 DISPPARAMS *pdispparams, /* [in] Parameter list */
714 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
715 VARIANT *pvarResult) /* [out] Destination for resulting variant */
717 /* position is counted backwards */
718 UINT pos;
720 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
721 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
722 if (*position < pdispparams->cArgs) {
723 /* positional arg? */
724 pos = pdispparams->cArgs - *position - 1;
725 } else {
726 /* FIXME: is this how to handle named args? */
727 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
728 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
730 if (pos==pdispparams->cNamedArgs)
731 return DISP_E_PARAMNOTFOUND;
733 *position = pos;
734 return VariantCopyInd(pvarResult,
735 &pdispparams->rgvarg[pos]);
738 static HRESULT SummaryInfoImpl_Invoke(
739 AutomationObject* This,
740 DISPID dispIdMember,
741 REFIID riid,
742 LCID lcid,
743 WORD wFlags,
744 DISPPARAMS* pDispParams,
745 VARIANT* pVarResult,
746 EXCEPINFO* pExcepInfo,
747 UINT* puArgErr)
749 UINT ret;
750 VARIANTARG varg0, varg1;
751 FILETIME ft, ftlocal;
752 SYSTEMTIME st;
753 HRESULT hr;
755 VariantInit(&varg0);
756 VariantInit(&varg1);
758 switch (dispIdMember)
760 case DISPID_SUMMARYINFO_PROPERTY:
761 if (wFlags & DISPATCH_PROPERTYGET)
763 UINT type;
764 INT value;
765 DWORD size = 0;
766 DATE date;
767 LPWSTR str;
769 static WCHAR szEmpty[] = {0};
771 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
772 if (FAILED(hr)) return hr;
773 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
774 &ft, szEmpty, &size);
775 if (ret != ERROR_SUCCESS &&
776 ret != ERROR_MORE_DATA)
778 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
779 return DISP_E_EXCEPTION;
782 switch (type)
784 case VT_EMPTY:
785 break;
787 case VT_I2:
788 case VT_I4:
789 V_VT(pVarResult) = VT_I4;
790 V_I4(pVarResult) = value;
791 break;
793 case VT_LPSTR:
794 if (!(str = msi_alloc(++size * sizeof(WCHAR))))
795 ERR("Out of memory\n");
796 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
797 NULL, str, &size)) != ERROR_SUCCESS)
798 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
799 else
801 V_VT(pVarResult) = VT_BSTR;
802 V_BSTR(pVarResult) = SysAllocString(str);
804 msi_free(str);
805 break;
807 case VT_FILETIME:
808 FileTimeToLocalFileTime(&ft, &ftlocal);
809 FileTimeToSystemTime(&ftlocal, &st);
810 SystemTimeToVariantTime(&st, &date);
812 V_VT(pVarResult) = VT_DATE;
813 V_DATE(pVarResult) = date;
814 break;
816 default:
817 ERR("Unhandled variant type %d\n", type);
820 else if (wFlags & DISPATCH_PROPERTYPUT)
822 UINT posValue = DISPID_PROPERTYPUT;
824 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
825 if (FAILED(hr)) return hr;
826 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
827 if (FAILED(hr))
829 *puArgErr = posValue;
830 return hr;
833 switch (V_VT(&varg1))
835 case VT_I2:
836 case VT_I4:
837 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
838 break;
840 case VT_DATE:
841 VariantTimeToSystemTime(V_DATE(&varg1), &st);
842 SystemTimeToFileTime(&st, &ftlocal);
843 LocalFileTimeToFileTime(&ftlocal, &ft);
844 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
845 break;
847 case VT_BSTR:
848 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
849 break;
851 default:
852 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
853 VariantClear(&varg1);
854 return DISP_E_EXCEPTION;
857 if (ret != ERROR_SUCCESS)
859 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
860 return DISP_E_EXCEPTION;
863 else return DISP_E_MEMBERNOTFOUND;
864 break;
866 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
867 if (wFlags & DISPATCH_PROPERTYGET) {
868 UINT count;
869 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
870 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
871 else
873 V_VT(pVarResult) = VT_I4;
874 V_I4(pVarResult) = count;
877 else return DISP_E_MEMBERNOTFOUND;
878 break;
880 default:
881 return DISP_E_MEMBERNOTFOUND;
884 VariantClear(&varg1);
885 VariantClear(&varg0);
887 return S_OK;
890 static HRESULT RecordImpl_Invoke(
891 AutomationObject* This,
892 DISPID dispIdMember,
893 REFIID riid,
894 LCID lcid,
895 WORD wFlags,
896 DISPPARAMS* pDispParams,
897 VARIANT* pVarResult,
898 EXCEPINFO* pExcepInfo,
899 UINT* puArgErr)
901 WCHAR *szString;
902 DWORD dwLen;
903 UINT ret;
904 VARIANTARG varg0, varg1;
905 HRESULT hr;
907 VariantInit(&varg0);
908 VariantInit(&varg1);
910 switch (dispIdMember)
912 case DISPID_RECORD_FIELDCOUNT:
913 if (wFlags & DISPATCH_PROPERTYGET) {
914 V_VT(pVarResult) = VT_I4;
915 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
917 else return DISP_E_MEMBERNOTFOUND;
918 break;
920 case DISPID_RECORD_STRINGDATA:
921 if (wFlags & DISPATCH_PROPERTYGET) {
922 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
923 if (FAILED(hr)) return hr;
924 V_VT(pVarResult) = VT_BSTR;
925 V_BSTR(pVarResult) = NULL;
926 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
928 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
929 ERR("Out of memory\n");
930 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
931 V_BSTR(pVarResult) = SysAllocString(szString);
932 msi_free(szString);
934 if (ret != ERROR_SUCCESS)
935 ERR("MsiRecordGetString returned %d\n", ret);
936 } else if (wFlags & DISPATCH_PROPERTYPUT) {
937 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
938 if (FAILED(hr)) return hr;
939 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
940 if (FAILED(hr)) return hr;
941 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
943 VariantClear(&varg1);
944 ERR("MsiRecordSetString returned %d\n", ret);
945 return DISP_E_EXCEPTION;
948 else return DISP_E_MEMBERNOTFOUND;
949 break;
951 case DISPID_RECORD_INTEGERDATA:
952 if (wFlags & DISPATCH_PROPERTYGET) {
953 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
954 if (FAILED(hr)) return hr;
955 V_VT(pVarResult) = VT_I4;
956 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
957 } else if (wFlags & DISPATCH_PROPERTYPUT) {
958 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
959 if (FAILED(hr)) return hr;
960 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
961 if (FAILED(hr)) return hr;
962 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
964 ERR("MsiRecordSetInteger returned %d\n", ret);
965 return DISP_E_EXCEPTION;
968 else return DISP_E_MEMBERNOTFOUND;
969 break;
971 default:
972 return DISP_E_MEMBERNOTFOUND;
975 VariantClear(&varg1);
976 VariantClear(&varg0);
978 return S_OK;
981 static HRESULT ListImpl_Invoke(
982 AutomationObject* This,
983 DISPID dispIdMember,
984 REFIID riid,
985 LCID lcid,
986 WORD wFlags,
987 DISPPARAMS* pDispParams,
988 VARIANT* pVarResult,
989 EXCEPINFO* pExcepInfo,
990 UINT* puArgErr)
992 ListData *data = private_data(This);
993 HRESULT hr;
994 VARIANTARG varg0;
995 IUnknown *pUnk = NULL;
997 VariantInit(&varg0);
999 switch (dispIdMember)
1001 case DISPID_LIST__NEWENUM:
1002 if (wFlags & DISPATCH_METHOD) {
1003 V_VT(pVarResult) = VT_UNKNOWN;
1004 if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0)))
1005 V_UNKNOWN(pVarResult) = pUnk;
1006 else
1007 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
1009 else return DISP_E_MEMBERNOTFOUND;
1010 break;
1012 case DISPID_LIST_ITEM:
1013 if (wFlags & DISPATCH_PROPERTYGET) {
1014 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1015 if (FAILED(hr)) return hr;
1016 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount)
1017 return DISP_E_BADINDEX;
1018 VariantCopy(pVarResult, &data->pVars[V_I4(&varg0)]);
1020 else return DISP_E_MEMBERNOTFOUND;
1021 break;
1023 case DISPID_LIST_COUNT:
1024 if (wFlags & DISPATCH_PROPERTYGET) {
1025 V_VT(pVarResult) = VT_I4;
1026 V_I4(pVarResult) = data->ulCount;
1028 else return DISP_E_MEMBERNOTFOUND;
1029 break;
1031 default:
1032 return DISP_E_MEMBERNOTFOUND;
1035 VariantClear(&varg0);
1037 return S_OK;
1040 static void ListImpl_Free(AutomationObject *This)
1042 ListData *data = private_data(This);
1043 ULONG idx;
1045 for (idx=0; idx<data->ulCount; idx++)
1046 VariantClear(&data->pVars[idx]);
1047 msi_free(data->pVars);
1050 static HRESULT ViewImpl_Invoke(
1051 AutomationObject* This,
1052 DISPID dispIdMember,
1053 REFIID riid,
1054 LCID lcid,
1055 WORD wFlags,
1056 DISPPARAMS* pDispParams,
1057 VARIANT* pVarResult,
1058 EXCEPINFO* pExcepInfo,
1059 UINT* puArgErr)
1061 MSIHANDLE msiHandle;
1062 IDispatch *pDispatch = NULL;
1063 UINT ret;
1064 VARIANTARG varg0, varg1;
1065 HRESULT hr;
1067 VariantInit(&varg0);
1068 VariantInit(&varg1);
1070 switch (dispIdMember)
1072 case DISPID_VIEW_EXECUTE:
1073 if (wFlags & DISPATCH_METHOD)
1075 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1076 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1077 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1078 else
1079 MsiViewExecute(This->msiHandle, 0);
1081 else return DISP_E_MEMBERNOTFOUND;
1082 break;
1084 case DISPID_VIEW_FETCH:
1085 if (wFlags & DISPATCH_METHOD)
1087 V_VT(pVarResult) = VT_DISPATCH;
1088 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1090 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1091 V_DISPATCH(pVarResult) = pDispatch;
1092 else
1093 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1095 else if (ret == ERROR_NO_MORE_ITEMS)
1096 V_DISPATCH(pVarResult) = NULL;
1097 else
1099 ERR("MsiViewFetch returned %d\n", ret);
1100 return DISP_E_EXCEPTION;
1103 else return DISP_E_MEMBERNOTFOUND;
1104 break;
1106 case DISPID_VIEW_MODIFY:
1107 if (wFlags & DISPATCH_METHOD)
1109 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1110 if (FAILED(hr)) return hr;
1111 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1112 if (FAILED(hr)) return hr;
1113 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1114 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1116 VariantClear(&varg1);
1117 ERR("MsiViewModify returned %d\n", ret);
1118 return DISP_E_EXCEPTION;
1121 else return DISP_E_MEMBERNOTFOUND;
1122 break;
1124 case DISPID_VIEW_CLOSE:
1125 if (wFlags & DISPATCH_METHOD)
1127 MsiViewClose(This->msiHandle);
1129 else return DISP_E_MEMBERNOTFOUND;
1130 break;
1132 default:
1133 return DISP_E_MEMBERNOTFOUND;
1136 VariantClear(&varg1);
1137 VariantClear(&varg0);
1139 return S_OK;
1142 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
1143 DISPPARAMS* pDispParams,
1144 VARIANT* pVarResult,
1145 EXCEPINFO* pExcepInfo,
1146 UINT* puArgErr)
1148 if (!(wFlags & DISPATCH_METHOD))
1149 return DISP_E_MEMBERNOTFOUND;
1151 FIXME("\n");
1153 VariantInit(pVarResult);
1154 return S_OK;
1157 static HRESULT DatabaseImpl_Invoke(
1158 AutomationObject* This,
1159 DISPID dispIdMember,
1160 REFIID riid,
1161 LCID lcid,
1162 WORD wFlags,
1163 DISPPARAMS* pDispParams,
1164 VARIANT* pVarResult,
1165 EXCEPINFO* pExcepInfo,
1166 UINT* puArgErr)
1168 MSIHANDLE msiHandle;
1169 IDispatch *pDispatch = NULL;
1170 UINT ret;
1171 VARIANTARG varg0, varg1;
1172 HRESULT hr;
1174 VariantInit(&varg0);
1175 VariantInit(&varg1);
1177 switch (dispIdMember)
1179 case DISPID_DATABASE_SUMMARYINFORMATION:
1180 if (wFlags & DISPATCH_PROPERTYGET)
1182 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1183 if (FAILED(hr))
1184 V_I4(&varg0) = 0;
1186 V_VT(pVarResult) = VT_DISPATCH;
1187 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1189 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0);
1190 if (SUCCEEDED(hr))
1191 V_DISPATCH(pVarResult) = pDispatch;
1192 else
1193 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1195 else
1197 ERR("MsiGetSummaryInformation returned %d\n", ret);
1198 return DISP_E_EXCEPTION;
1201 else return DISP_E_MEMBERNOTFOUND;
1202 break;
1204 case DISPID_DATABASE_OPENVIEW:
1205 if (wFlags & DISPATCH_METHOD)
1207 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1208 if (FAILED(hr)) return hr;
1209 V_VT(pVarResult) = VT_DISPATCH;
1210 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1212 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1213 V_DISPATCH(pVarResult) = pDispatch;
1214 else
1215 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1217 else
1219 VariantClear(&varg0);
1220 ERR("MsiDatabaseOpenView returned %d\n", ret);
1221 return DISP_E_EXCEPTION;
1224 else return DISP_E_MEMBERNOTFOUND;
1225 break;
1227 case DISPID_INSTALLER_LASTERRORRECORD:
1228 return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
1229 pVarResult, pExcepInfo,
1230 puArgErr);
1232 default:
1233 return DISP_E_MEMBERNOTFOUND;
1236 VariantClear(&varg1);
1237 VariantClear(&varg0);
1239 return S_OK;
1242 static HRESULT create_database(MSIHANDLE msiHandle, IDispatch **dispatch)
1244 AutomationObject *database;
1245 HRESULT hr;
1247 TRACE("(%d %p)\n", msiHandle, dispatch);
1249 database = msi_alloc(sizeof(AutomationObject));
1250 if (!database) return E_OUTOFMEMORY;
1252 hr = init_automation_object(database, msiHandle, &DIID_Database, DatabaseImpl_Invoke, NULL);
1253 if (hr != S_OK)
1255 msi_free(database);
1256 return hr;
1259 *dispatch = &database->IDispatch_iface;
1261 return hr;
1264 static HRESULT SessionImpl_Invoke(
1265 AutomationObject* This,
1266 DISPID dispIdMember,
1267 REFIID riid,
1268 LCID lcid,
1269 WORD wFlags,
1270 DISPPARAMS* pDispParams,
1271 VARIANT* pVarResult,
1272 EXCEPINFO* pExcepInfo,
1273 UINT* puArgErr)
1275 SessionObject *session = (SessionObject*)This;
1276 WCHAR *szString;
1277 DWORD dwLen;
1278 MSIHANDLE msiHandle;
1279 LANGID langId;
1280 UINT ret;
1281 INSTALLSTATE iInstalled, iAction;
1282 VARIANTARG varg0, varg1;
1283 HRESULT hr;
1285 VariantInit(&varg0);
1286 VariantInit(&varg1);
1288 switch (dispIdMember)
1290 case DISPID_SESSION_INSTALLER:
1291 if (wFlags & DISPATCH_PROPERTYGET) {
1292 V_VT(pVarResult) = VT_DISPATCH;
1293 IDispatch_AddRef(session->installer);
1294 V_DISPATCH(pVarResult) = session->installer;
1296 else return DISP_E_MEMBERNOTFOUND;
1297 break;
1299 case DISPID_SESSION_PROPERTY:
1300 if (wFlags & DISPATCH_PROPERTYGET) {
1301 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1302 if (FAILED(hr)) return hr;
1303 V_VT(pVarResult) = VT_BSTR;
1304 V_BSTR(pVarResult) = NULL;
1305 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1307 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1308 ERR("Out of memory\n");
1309 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1310 V_BSTR(pVarResult) = SysAllocString(szString);
1311 msi_free(szString);
1313 if (ret != ERROR_SUCCESS)
1314 ERR("MsiGetProperty returned %d\n", ret);
1315 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1316 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1317 if (FAILED(hr)) return hr;
1318 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1319 if (FAILED(hr)) {
1320 VariantClear(&varg0);
1321 return hr;
1323 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1325 VariantClear(&varg0);
1326 VariantClear(&varg1);
1327 ERR("MsiSetProperty returned %d\n", ret);
1328 return DISP_E_EXCEPTION;
1331 else return DISP_E_MEMBERNOTFOUND;
1332 break;
1334 case DISPID_SESSION_LANGUAGE:
1335 if (wFlags & DISPATCH_PROPERTYGET) {
1336 langId = MsiGetLanguage(This->msiHandle);
1337 V_VT(pVarResult) = VT_I4;
1338 V_I4(pVarResult) = langId;
1340 else return DISP_E_MEMBERNOTFOUND;
1341 break;
1343 case DISPID_SESSION_MODE:
1344 if (wFlags & DISPATCH_PROPERTYGET) {
1345 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1346 if (FAILED(hr)) return hr;
1347 V_VT(pVarResult) = VT_BOOL;
1348 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1349 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1350 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1351 if (FAILED(hr)) return hr;
1352 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1353 if (FAILED(hr)) return hr;
1354 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1356 ERR("MsiSetMode returned %d\n", ret);
1357 return DISP_E_EXCEPTION;
1360 else return DISP_E_MEMBERNOTFOUND;
1361 break;
1363 case DISPID_SESSION_DATABASE:
1364 if (wFlags & DISPATCH_PROPERTYGET) {
1365 V_VT(pVarResult) = VT_DISPATCH;
1366 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1368 IDispatch *dispatch;
1370 if (SUCCEEDED(hr = create_database(msiHandle, &dispatch)))
1371 V_DISPATCH(pVarResult) = dispatch;
1372 else
1373 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1375 else
1377 ERR("MsiGetActiveDatabase failed\n");
1378 return DISP_E_EXCEPTION;
1381 else return DISP_E_MEMBERNOTFOUND;
1382 break;
1384 case DISPID_SESSION_DOACTION:
1385 if (wFlags & DISPATCH_METHOD) {
1386 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1387 if (FAILED(hr)) return hr;
1388 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1389 V_VT(pVarResult) = VT_I4;
1390 switch (ret)
1392 case ERROR_FUNCTION_NOT_CALLED:
1393 V_I4(pVarResult) = msiDoActionStatusNoAction;
1394 break;
1395 case ERROR_SUCCESS:
1396 V_I4(pVarResult) = msiDoActionStatusSuccess;
1397 break;
1398 case ERROR_INSTALL_USEREXIT:
1399 V_I4(pVarResult) = msiDoActionStatusUserExit;
1400 break;
1401 case ERROR_INSTALL_FAILURE:
1402 V_I4(pVarResult) = msiDoActionStatusFailure;
1403 break;
1404 case ERROR_INSTALL_SUSPEND:
1405 V_I4(pVarResult) = msiDoActionStatusSuspend;
1406 break;
1407 case ERROR_MORE_DATA:
1408 V_I4(pVarResult) = msiDoActionStatusFinished;
1409 break;
1410 case ERROR_INVALID_HANDLE_STATE:
1411 V_I4(pVarResult) = msiDoActionStatusWrongState;
1412 break;
1413 case ERROR_INVALID_DATA:
1414 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1415 break;
1416 default:
1417 VariantClear(&varg0);
1418 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1419 return DISP_E_EXCEPTION;
1422 else return DISP_E_MEMBERNOTFOUND;
1423 break;
1425 case DISPID_SESSION_EVALUATECONDITION:
1426 if (wFlags & DISPATCH_METHOD) {
1427 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1428 if (FAILED(hr)) return hr;
1429 V_VT(pVarResult) = VT_I4;
1430 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1432 else return DISP_E_MEMBERNOTFOUND;
1433 break;
1435 case DISPID_SESSION_MESSAGE:
1436 if(!(wFlags & DISPATCH_METHOD))
1437 return DISP_E_MEMBERNOTFOUND;
1439 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1440 if (FAILED(hr)) return hr;
1441 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1442 if (FAILED(hr)) return hr;
1444 V_VT(pVarResult) = VT_I4;
1445 V_I4(pVarResult) =
1446 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
1447 break;
1449 case DISPID_SESSION_SETINSTALLLEVEL:
1450 if (wFlags & DISPATCH_METHOD) {
1451 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1452 if (FAILED(hr)) return hr;
1453 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1455 ERR("MsiSetInstallLevel returned %d\n", ret);
1456 return DISP_E_EXCEPTION;
1459 else return DISP_E_MEMBERNOTFOUND;
1460 break;
1462 case DISPID_SESSION_FEATURECURRENTSTATE:
1463 if (wFlags & DISPATCH_PROPERTYGET) {
1464 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1465 if (FAILED(hr)) return hr;
1466 V_VT(pVarResult) = VT_I4;
1467 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1468 V_I4(pVarResult) = iInstalled;
1469 else
1471 ERR("MsiGetFeatureState returned %d\n", ret);
1472 V_I4(pVarResult) = msiInstallStateUnknown;
1475 else return DISP_E_MEMBERNOTFOUND;
1476 break;
1478 case DISPID_SESSION_FEATUREREQUESTSTATE:
1479 if (wFlags & DISPATCH_PROPERTYGET) {
1480 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1481 if (FAILED(hr)) return hr;
1482 V_VT(pVarResult) = VT_I4;
1483 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1484 V_I4(pVarResult) = iAction;
1485 else
1487 ERR("MsiGetFeatureState returned %d\n", ret);
1488 V_I4(pVarResult) = msiInstallStateUnknown;
1490 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1491 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1492 if (FAILED(hr)) return hr;
1493 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1494 if (FAILED(hr)) {
1495 VariantClear(&varg0);
1496 return hr;
1498 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1500 VariantClear(&varg0);
1501 ERR("MsiSetFeatureState returned %d\n", ret);
1502 return DISP_E_EXCEPTION;
1505 else return DISP_E_MEMBERNOTFOUND;
1506 break;
1508 default:
1509 return DISP_E_MEMBERNOTFOUND;
1512 VariantClear(&varg1);
1513 VariantClear(&varg0);
1515 return S_OK;
1518 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1519 * registry value type. Used by Installer::RegistryValue. */
1520 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1522 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1523 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1524 WCHAR *szString = (WCHAR *)lpData;
1525 LPWSTR szNewString = NULL;
1526 DWORD dwNewSize = 0;
1527 int idx;
1529 switch (dwType)
1531 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1532 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1533 idx = (dwSize/sizeof(WCHAR))-1;
1534 while (idx >= 0 && !szString[idx]) idx--;
1535 for (; idx >= 0; idx--)
1536 if (!szString[idx]) szString[idx] = '\n';
1537 /* fall through */
1538 case REG_SZ:
1539 V_VT(pVarResult) = VT_BSTR;
1540 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1541 break;
1543 case REG_EXPAND_SZ:
1544 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1545 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1546 else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1547 ERR("Out of memory\n");
1548 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1549 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1550 else
1552 V_VT(pVarResult) = VT_BSTR;
1553 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1555 msi_free(szNewString);
1556 break;
1558 case REG_DWORD:
1559 V_VT(pVarResult) = VT_I4;
1560 V_I4(pVarResult) = *((DWORD *)lpData);
1561 break;
1563 case REG_QWORD:
1564 V_VT(pVarResult) = VT_BSTR;
1565 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1566 break;
1568 case REG_BINARY:
1569 V_VT(pVarResult) = VT_BSTR;
1570 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1571 break;
1573 case REG_NONE:
1574 V_VT(pVarResult) = VT_EMPTY;
1575 break;
1577 default:
1578 FIXME("Unhandled registry value type %d\n", dwType);
1582 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1583 DISPPARAMS* pDispParams,
1584 VARIANT* pVarResult,
1585 EXCEPINFO* pExcepInfo,
1586 UINT* puArgErr)
1588 HRESULT hr;
1589 VARIANTARG varg0;
1590 MSIHANDLE hrec;
1591 IDispatch* dispatch;
1593 if (!(wFlags & DISPATCH_METHOD))
1594 return DISP_E_MEMBERNOTFOUND;
1596 VariantInit(&varg0);
1597 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1598 if (FAILED(hr))
1599 return hr;
1601 V_VT(pVarResult) = VT_DISPATCH;
1603 hrec = MsiCreateRecord(V_I4(&varg0));
1604 if (!hrec)
1605 return DISP_E_EXCEPTION;
1607 hr = create_automation_object(hrec, NULL, (LPVOID*)&dispatch,
1608 &DIID_Record, RecordImpl_Invoke, NULL, 0);
1609 if (SUCCEEDED(hr))
1610 V_DISPATCH(pVarResult) = dispatch;
1612 return hr;
1615 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1616 WORD wFlags,
1617 DISPPARAMS* pDispParams,
1618 VARIANT* pVarResult,
1619 EXCEPINFO* pExcepInfo,
1620 UINT* puArgErr)
1622 UINT ret;
1623 HRESULT hr;
1624 MSIHANDLE hpkg;
1625 IDispatch* dispatch;
1626 VARIANTARG varg0, varg1;
1628 if (!(wFlags & DISPATCH_METHOD))
1629 return DISP_E_MEMBERNOTFOUND;
1631 if (pDispParams->cArgs == 0)
1632 return DISP_E_TYPEMISMATCH;
1634 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1635 return DISP_E_TYPEMISMATCH;
1637 VariantInit(&varg0);
1638 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1639 if (FAILED(hr))
1640 return hr;
1642 VariantInit(&varg1);
1643 if (pDispParams->cArgs == 2)
1645 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1646 if (FAILED(hr))
1647 goto done;
1649 else
1651 V_VT(&varg1) = VT_I4;
1652 V_I4(&varg1) = 0;
1655 V_VT(pVarResult) = VT_DISPATCH;
1657 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1658 if (ret != ERROR_SUCCESS)
1660 hr = DISP_E_EXCEPTION;
1661 goto done;
1664 hr = create_session(hpkg, &This->IDispatch_iface, &dispatch);
1665 if (SUCCEEDED(hr))
1666 V_DISPATCH(pVarResult) = dispatch;
1668 done:
1669 VariantClear(&varg0);
1670 VariantClear(&varg1);
1671 return hr;
1674 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1675 DISPPARAMS* pDispParams,
1676 VARIANT* pVarResult,
1677 EXCEPINFO* pExcepInfo,
1678 UINT* puArgErr)
1680 HRESULT hr;
1681 VARIANTARG varg0;
1683 if (!(wFlags & DISPATCH_METHOD))
1684 return DISP_E_MEMBERNOTFOUND;
1686 VariantInit(&varg0);
1687 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1688 if (FAILED(hr))
1689 return hr;
1691 FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1693 VariantInit(pVarResult);
1695 VariantClear(&varg0);
1696 return S_OK;
1699 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1700 DISPPARAMS* pDispParams,
1701 VARIANT* pVarResult,
1702 EXCEPINFO* pExcepInfo,
1703 UINT* puArgErr)
1705 UINT ret;
1706 HRESULT hr;
1707 MSIHANDLE hdb;
1708 IDispatch* dispatch;
1709 VARIANTARG varg0, varg1;
1711 if (!(wFlags & DISPATCH_METHOD))
1712 return DISP_E_MEMBERNOTFOUND;
1714 VariantInit(&varg0);
1715 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1716 if (FAILED(hr))
1717 return hr;
1719 VariantInit(&varg1);
1720 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1721 if (FAILED(hr))
1722 goto done;
1724 V_VT(pVarResult) = VT_DISPATCH;
1726 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1727 if (ret != ERROR_SUCCESS)
1729 hr = DISP_E_EXCEPTION;
1730 goto done;
1733 hr = create_database(hdb, &dispatch);
1734 if (SUCCEEDED(hr))
1735 V_DISPATCH(pVarResult) = dispatch;
1737 done:
1738 VariantClear(&varg0);
1739 VariantClear(&varg1);
1740 return hr;
1743 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1744 DISPPARAMS* pDispParams,
1745 VARIANT* pVarResult,
1746 EXCEPINFO* pExcepInfo,
1747 UINT* puArgErr)
1749 if (!(wFlags & DISPATCH_METHOD))
1750 return DISP_E_MEMBERNOTFOUND;
1752 FIXME("\n");
1754 VariantInit(pVarResult);
1755 return S_OK;
1758 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1759 DISPPARAMS* pDispParams,
1760 VARIANT* pVarResult,
1761 EXCEPINFO* pExcepInfo,
1762 UINT* puArgErr)
1764 HRESULT hr;
1765 VARIANTARG varg0;
1766 INSTALLUILEVEL ui;
1768 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1769 return DISP_E_MEMBERNOTFOUND;
1771 if (wFlags & DISPATCH_PROPERTYPUT)
1773 VariantInit(&varg0);
1774 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1775 if (FAILED(hr))
1776 return hr;
1778 ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1779 if (ui == INSTALLUILEVEL_NOCHANGE)
1780 return DISP_E_EXCEPTION;
1782 else if (wFlags & DISPATCH_PROPERTYGET)
1784 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1785 if (ui == INSTALLUILEVEL_NOCHANGE)
1786 return DISP_E_EXCEPTION;
1788 V_VT(pVarResult) = VT_I4;
1789 V_I4(pVarResult) = ui;
1792 return S_OK;
1795 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1796 DISPPARAMS* pDispParams,
1797 VARIANT* pVarResult,
1798 EXCEPINFO* pExcepInfo,
1799 UINT* puArgErr)
1801 if (!(wFlags & DISPATCH_METHOD))
1802 return DISP_E_MEMBERNOTFOUND;
1804 FIXME("\n");
1806 VariantInit(pVarResult);
1807 return S_OK;
1810 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1811 DISPPARAMS* pDispParams,
1812 VARIANT* pVarResult,
1813 EXCEPINFO* pExcepInfo,
1814 UINT* puArgErr)
1816 UINT ret;
1817 HRESULT hr;
1818 VARIANTARG varg0, varg1;
1820 if (!(wFlags & DISPATCH_METHOD))
1821 return DISP_E_MEMBERNOTFOUND;
1823 VariantInit(&varg0);
1824 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1825 if (FAILED(hr))
1826 return hr;
1828 VariantInit(&varg1);
1829 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1830 if (FAILED(hr))
1831 goto done;
1833 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1834 if (ret != ERROR_SUCCESS)
1836 hr = DISP_E_EXCEPTION;
1837 goto done;
1840 done:
1841 VariantClear(&varg0);
1842 VariantClear(&varg1);
1843 return hr;
1846 static HRESULT InstallerImpl_Version(WORD wFlags,
1847 VARIANT* pVarResult,
1848 EXCEPINFO* pExcepInfo,
1849 UINT* puArgErr)
1851 HRESULT hr;
1852 DLLVERSIONINFO verinfo;
1853 WCHAR version[MAX_PATH];
1855 static const WCHAR format[] = {
1856 '%','d','.','%','d','.','%','d','.','%','d',0};
1858 if (!(wFlags & DISPATCH_PROPERTYGET))
1859 return DISP_E_MEMBERNOTFOUND;
1861 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1862 hr = DllGetVersion(&verinfo);
1863 if (FAILED(hr))
1864 return hr;
1866 sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1867 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1869 V_VT(pVarResult) = VT_BSTR;
1870 V_BSTR(pVarResult) = SysAllocString(version);
1871 return S_OK;
1874 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1875 DISPPARAMS* pDispParams,
1876 VARIANT* pVarResult,
1877 EXCEPINFO* pExcepInfo,
1878 UINT* puArgErr)
1880 if (!(wFlags & DISPATCH_METHOD))
1881 return DISP_E_MEMBERNOTFOUND;
1883 FIXME("\n");
1885 VariantInit(pVarResult);
1886 return S_OK;
1889 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1890 DISPPARAMS* pDispParams,
1891 VARIANT* pVarResult,
1892 EXCEPINFO* pExcepInfo,
1893 UINT* puArgErr)
1895 UINT ret;
1896 HKEY hkey = NULL;
1897 HRESULT hr;
1898 UINT posValue;
1899 DWORD type, size;
1900 LPWSTR szString = NULL;
1901 VARIANTARG varg0, varg1, varg2;
1903 if (!(wFlags & DISPATCH_METHOD))
1904 return DISP_E_MEMBERNOTFOUND;
1906 VariantInit(&varg0);
1907 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1908 if (FAILED(hr))
1909 return hr;
1911 VariantInit(&varg1);
1912 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1913 if (FAILED(hr))
1914 goto done;
1916 /* Save valuePos so we can save puArgErr if we are unable to do our type
1917 * conversions.
1919 posValue = 2;
1920 VariantInit(&varg2);
1921 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1922 if (FAILED(hr))
1923 goto done;
1925 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
1926 V_I4(&varg0) <= REG_INDEX_DYN_DATA)
1928 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
1931 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1933 /* Only VT_EMPTY case can do anything if the key doesn't exist. */
1934 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
1936 hr = DISP_E_BADINDEX;
1937 goto done;
1940 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1941 switch (V_VT(&varg2))
1943 /* Return VT_BOOL clarifying whether registry key exists or not. */
1944 case VT_EMPTY:
1945 V_VT(pVarResult) = VT_BOOL;
1946 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1947 break;
1949 /* Return the value of specified key if it exists. */
1950 case VT_BSTR:
1951 ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
1952 NULL, NULL, NULL, &size);
1953 if (ret != ERROR_SUCCESS)
1955 hr = DISP_E_BADINDEX;
1956 goto done;
1959 szString = msi_alloc(size);
1960 if (!szString)
1962 hr = E_OUTOFMEMORY;
1963 goto done;
1966 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
1967 &type, (LPBYTE)szString, &size);
1968 if (ret != ERROR_SUCCESS)
1970 msi_free(szString);
1971 hr = DISP_E_BADINDEX;
1972 goto done;
1975 variant_from_registry_value(pVarResult, type,
1976 (LPBYTE)szString, size);
1977 msi_free(szString);
1978 break;
1980 /* Try to make it into VT_I4, can use VariantChangeType for this. */
1981 default:
1982 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1983 if (FAILED(hr))
1985 if (hr == DISP_E_TYPEMISMATCH)
1986 *puArgErr = posValue;
1988 goto done;
1991 /* Retrieve class name or maximum value name or subkey name size. */
1992 if (!V_I4(&varg2))
1993 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
1994 NULL, NULL, NULL, NULL, NULL, NULL);
1995 else if (V_I4(&varg2) > 0)
1996 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
1997 NULL, NULL, &size, NULL, NULL, NULL);
1998 else /* V_I4(&varg2) < 0 */
1999 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
2000 NULL, NULL, NULL, NULL, NULL, NULL);
2002 if (ret != ERROR_SUCCESS)
2003 goto done;
2005 szString = msi_alloc(++size * sizeof(WCHAR));
2006 if (!szString)
2008 hr = E_OUTOFMEMORY;
2009 goto done;
2012 if (!V_I4(&varg2))
2013 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
2014 NULL, NULL, NULL, NULL, NULL, NULL);
2015 else if (V_I4(&varg2) > 0)
2016 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
2017 &size, 0, 0, NULL, NULL);
2018 else /* V_I4(&varg2) < 0 */
2019 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
2021 if (ret == ERROR_SUCCESS)
2023 V_VT(pVarResult) = VT_BSTR;
2024 V_BSTR(pVarResult) = SysAllocString(szString);
2027 msi_free(szString);
2030 done:
2031 VariantClear(&varg0);
2032 VariantClear(&varg1);
2033 VariantClear(&varg2);
2034 RegCloseKey(hkey);
2035 return hr;
2038 static HRESULT InstallerImpl_Environment(WORD wFlags,
2039 DISPPARAMS* pDispParams,
2040 VARIANT* pVarResult,
2041 EXCEPINFO* pExcepInfo,
2042 UINT* puArgErr)
2044 if (!(wFlags & DISPATCH_METHOD))
2045 return DISP_E_MEMBERNOTFOUND;
2047 FIXME("\n");
2049 VariantInit(pVarResult);
2050 return S_OK;
2053 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2054 DISPPARAMS* pDispParams,
2055 VARIANT* pVarResult,
2056 EXCEPINFO* pExcepInfo,
2057 UINT* puArgErr)
2059 if (!(wFlags & DISPATCH_METHOD))
2060 return DISP_E_MEMBERNOTFOUND;
2062 FIXME("\n");
2064 VariantInit(pVarResult);
2065 return S_OK;
2068 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2069 DISPPARAMS* pDispParams,
2070 VARIANT* pVarResult,
2071 EXCEPINFO* pExcepInfo,
2072 UINT* puArgErr)
2074 if (!(wFlags & DISPATCH_METHOD))
2075 return DISP_E_MEMBERNOTFOUND;
2077 FIXME("\n");
2079 VariantInit(pVarResult);
2080 return S_OK;
2083 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2084 DISPPARAMS* pDispParams,
2085 VARIANT* pVarResult,
2086 EXCEPINFO* pExcepInfo,
2087 UINT* puArgErr)
2089 if (!(wFlags & DISPATCH_METHOD))
2090 return DISP_E_MEMBERNOTFOUND;
2092 FIXME("\n");
2094 VariantInit(pVarResult);
2095 return S_OK;
2098 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2099 DISPPARAMS* pDispParams,
2100 VARIANT* pVarResult,
2101 EXCEPINFO* pExcepInfo,
2102 UINT* puArgErr)
2104 HRESULT hr;
2105 VARIANTARG varg0;
2107 if (!(wFlags & DISPATCH_PROPERTYGET))
2108 return DISP_E_MEMBERNOTFOUND;
2110 VariantInit(&varg0);
2111 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2112 if (FAILED(hr))
2113 return hr;
2115 V_VT(pVarResult) = VT_I4;
2116 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2118 VariantClear(&varg0);
2119 return S_OK;
2122 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2123 DISPPARAMS* pDispParams,
2124 VARIANT* pVarResult,
2125 EXCEPINFO* pExcepInfo,
2126 UINT* puArgErr)
2128 UINT ret;
2129 HRESULT hr;
2130 DWORD size;
2131 LPWSTR str = NULL;
2132 VARIANTARG varg0, varg1;
2134 if (!(wFlags & DISPATCH_PROPERTYGET))
2135 return DISP_E_MEMBERNOTFOUND;
2137 VariantInit(&varg0);
2138 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2139 if (FAILED(hr))
2140 return hr;
2142 VariantInit(&varg1);
2143 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2144 if (FAILED(hr))
2145 goto done;
2147 V_VT(pVarResult) = VT_BSTR;
2148 V_BSTR(pVarResult) = NULL;
2150 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2151 if (ret != ERROR_SUCCESS)
2153 hr = DISP_E_EXCEPTION;
2154 goto done;
2157 str = msi_alloc(++size * sizeof(WCHAR));
2158 if (!str)
2160 hr = E_OUTOFMEMORY;
2161 goto done;
2164 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2165 if (ret != ERROR_SUCCESS)
2167 hr = DISP_E_EXCEPTION;
2168 goto done;
2171 V_BSTR(pVarResult) = SysAllocString(str);
2172 hr = S_OK;
2174 done:
2175 msi_free(str);
2176 VariantClear(&varg0);
2177 VariantClear(&varg1);
2178 return hr;
2181 static void cleanup_products(IDispatch* dispatch, ULONG count)
2183 UINT i;
2184 ListData* ldata = private_data((AutomationObject *)dispatch);
2186 for (i = 0; i < count - 1; i++)
2187 VariantClear(&ldata->pVars[i]);
2189 ldata->ulCount = 0;
2190 msi_free(ldata->pVars);
2192 IDispatch_Release(dispatch);
2195 static HRESULT InstallerImpl_Products(WORD wFlags,
2196 DISPPARAMS* pDispParams,
2197 VARIANT* pVarResult,
2198 EXCEPINFO* pExcepInfo,
2199 UINT* puArgErr)
2201 UINT ret;
2202 HRESULT hr;
2203 ULONG idx = 0;
2204 ListData *ldata;
2205 IDispatch *dispatch;
2206 WCHAR product[GUID_SIZE];
2208 if (!(wFlags & DISPATCH_PROPERTYGET))
2209 return DISP_E_MEMBERNOTFOUND;
2211 /* Find number of products. */
2212 while ((ret = MsiEnumProductsW(idx, product)) == ERROR_SUCCESS)
2213 idx++;
2215 if (ret != ERROR_NO_MORE_ITEMS)
2216 return DISP_E_EXCEPTION;
2218 V_VT(pVarResult) = VT_DISPATCH;
2219 hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2220 &DIID_StringList, ListImpl_Invoke,
2221 ListImpl_Free, sizeof(ListData));
2222 if (FAILED(hr))
2223 return hr;
2225 V_DISPATCH(pVarResult) = dispatch;
2227 /* Save product strings. */
2228 ldata = private_data((AutomationObject *)dispatch);
2229 ldata->ulCount = 0;
2230 ldata->pVars = msi_alloc_zero(sizeof(VARIANT) * idx);
2231 if (!ldata->pVars)
2233 IDispatch_Release(dispatch);
2234 return E_OUTOFMEMORY;
2237 ldata->ulCount = idx;
2238 for (idx = 0; idx < ldata->ulCount; idx++)
2240 ret = MsiEnumProductsW(idx, product);
2241 if (ret != ERROR_SUCCESS)
2243 cleanup_products(dispatch, idx - 1);
2244 return DISP_E_EXCEPTION;
2247 VariantInit(&ldata->pVars[idx]);
2248 V_VT(&ldata->pVars[idx]) = VT_BSTR;
2249 V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2252 return S_OK;
2255 static HRESULT InstallerImpl_RelatedProducts(WORD wFlags,
2256 DISPPARAMS* pDispParams,
2257 VARIANT* pVarResult,
2258 EXCEPINFO* pExcepInfo,
2259 UINT* puArgErr)
2261 UINT ret;
2262 ULONG idx;
2263 HRESULT hr;
2264 ListData *ldata;
2265 VARIANTARG varg0;
2266 IDispatch* dispatch;
2267 WCHAR product[GUID_SIZE];
2269 if (!(wFlags & DISPATCH_PROPERTYGET))
2270 return DISP_E_MEMBERNOTFOUND;
2272 VariantInit(&varg0);
2273 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2274 if (FAILED(hr))
2275 return hr;
2277 /* Find number of related products. */
2278 idx = 0;
2281 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2282 if (ret == ERROR_SUCCESS)
2283 idx++;
2284 } while (ret == ERROR_SUCCESS);
2286 if (ret != ERROR_NO_MORE_ITEMS)
2288 hr = DISP_E_EXCEPTION;
2289 goto done;
2292 V_VT(pVarResult) = VT_DISPATCH;
2294 hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2295 &DIID_StringList, ListImpl_Invoke,
2296 ListImpl_Free, sizeof(ListData));
2297 if (FAILED(hr))
2298 goto done;
2300 V_DISPATCH(pVarResult) = dispatch;
2302 /* Save product strings. */
2303 ldata = private_data((AutomationObject *)dispatch);
2304 ldata->pVars = msi_alloc(sizeof(VARIANT) * idx);
2305 if (!ldata->pVars)
2307 IDispatch_Release(dispatch);
2308 hr = E_OUTOFMEMORY;
2309 goto done;
2312 ldata->ulCount = idx;
2313 for (idx = 0; idx < ldata->ulCount; idx++)
2315 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2316 if (ret != ERROR_SUCCESS)
2318 cleanup_products(dispatch, idx - 1);
2319 hr = DISP_E_EXCEPTION;
2320 goto done;
2323 VariantInit(&ldata->pVars[idx]);
2324 V_VT(&ldata->pVars[idx]) = VT_BSTR;
2325 V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2328 hr = S_OK;
2330 done:
2331 VariantClear(&varg0);
2332 return hr;
2335 static HRESULT InstallerImpl_Invoke(
2336 AutomationObject* This,
2337 DISPID dispIdMember,
2338 REFIID riid,
2339 LCID lcid,
2340 WORD wFlags,
2341 DISPPARAMS* pDispParams,
2342 VARIANT* pVarResult,
2343 EXCEPINFO* pExcepInfo,
2344 UINT* puArgErr)
2346 switch (dispIdMember)
2348 case DISPID_INSTALLER_CREATERECORD:
2349 return InstallerImpl_CreateRecord(wFlags, pDispParams,
2350 pVarResult, pExcepInfo, puArgErr);
2352 case DISPID_INSTALLER_OPENPACKAGE:
2353 return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2354 pVarResult, pExcepInfo, puArgErr);
2356 case DISPID_INSTALLER_OPENPRODUCT:
2357 return InstallerImpl_OpenProduct(wFlags, pDispParams,
2358 pVarResult, pExcepInfo, puArgErr);
2360 case DISPID_INSTALLER_OPENDATABASE:
2361 return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2362 pVarResult, pExcepInfo, puArgErr);
2364 case DISPID_INSTALLER_SUMMARYINFORMATION:
2365 return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2366 pVarResult, pExcepInfo,
2367 puArgErr);
2369 case DISPID_INSTALLER_UILEVEL:
2370 return InstallerImpl_UILevel(wFlags, pDispParams,
2371 pVarResult, pExcepInfo, puArgErr);
2373 case DISPID_INSTALLER_ENABLELOG:
2374 return InstallerImpl_EnableLog(wFlags, pDispParams,
2375 pVarResult, pExcepInfo, puArgErr);
2377 case DISPID_INSTALLER_INSTALLPRODUCT:
2378 return InstallerImpl_InstallProduct(wFlags, pDispParams,
2379 pVarResult, pExcepInfo,
2380 puArgErr);
2382 case DISPID_INSTALLER_VERSION:
2383 return InstallerImpl_Version(wFlags, pVarResult,
2384 pExcepInfo, puArgErr);
2386 case DISPID_INSTALLER_LASTERRORRECORD:
2387 return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2388 pVarResult, pExcepInfo,
2389 puArgErr);
2391 case DISPID_INSTALLER_REGISTRYVALUE:
2392 return InstallerImpl_RegistryValue(wFlags, pDispParams,
2393 pVarResult, pExcepInfo,
2394 puArgErr);
2396 case DISPID_INSTALLER_ENVIRONMENT:
2397 return InstallerImpl_Environment(wFlags, pDispParams,
2398 pVarResult, pExcepInfo, puArgErr);
2400 case DISPID_INSTALLER_FILEATTRIBUTES:
2401 return InstallerImpl_FileAttributes(wFlags, pDispParams,
2402 pVarResult, pExcepInfo,
2403 puArgErr);
2405 case DISPID_INSTALLER_FILESIZE:
2406 return InstallerImpl_FileSize(wFlags, pDispParams,
2407 pVarResult, pExcepInfo, puArgErr);
2409 case DISPID_INSTALLER_FILEVERSION:
2410 return InstallerImpl_FileVersion(wFlags, pDispParams,
2411 pVarResult, pExcepInfo, puArgErr);
2413 case DISPID_INSTALLER_PRODUCTSTATE:
2414 return InstallerImpl_ProductState(wFlags, pDispParams,
2415 pVarResult, pExcepInfo, puArgErr);
2417 case DISPID_INSTALLER_PRODUCTINFO:
2418 return InstallerImpl_ProductInfo(wFlags, pDispParams,
2419 pVarResult, pExcepInfo, puArgErr);
2421 case DISPID_INSTALLER_PRODUCTS:
2422 return InstallerImpl_Products(wFlags, pDispParams,
2423 pVarResult, pExcepInfo, puArgErr);
2425 case DISPID_INSTALLER_RELATEDPRODUCTS:
2426 return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2427 pVarResult, pExcepInfo,
2428 puArgErr);
2430 default:
2431 return DISP_E_MEMBERNOTFOUND;
2435 HRESULT create_msiserver(IUnknown *outer, void **ppObj)
2437 AutomationObject *installer;
2438 HRESULT hr;
2440 TRACE("(%p %p)\n", outer, ppObj);
2442 if (outer)
2443 return CLASS_E_NOAGGREGATION;
2445 installer = msi_alloc(sizeof(AutomationObject));
2446 if (!installer) return E_OUTOFMEMORY;
2448 hr = init_automation_object(installer, 0, &DIID_Installer, InstallerImpl_Invoke, NULL);
2449 if (hr != S_OK)
2451 msi_free(installer);
2452 return hr;
2455 *ppObj = &installer->IDispatch_iface;
2457 return hr;
2460 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp)
2462 SessionObject *session;
2463 HRESULT hr;
2465 session = msi_alloc(sizeof(SessionObject));
2466 if (!session) return E_OUTOFMEMORY;
2468 hr = init_automation_object(&session->autoobj, msiHandle, &DIID_Session, SessionImpl_Invoke, NULL);
2469 if (hr != S_OK)
2471 msi_free(session);
2472 return hr;
2475 session->installer = installer;
2476 *disp = &session->autoobj.IDispatch_iface;
2478 return hr;