msi: Implement session object directly on top of automation object.
[wine/multimedia.git] / dlls / msi / automation.c
blobb416007a324359eceb8ac344a775ce2d5dd0bb2d
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 /* Load type info so we don't have to process GetIDsOfNames */
107 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
109 HRESULT hr;
110 LPTYPELIB pLib = NULL;
111 LPTYPEINFO pInfo = NULL;
112 static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
114 TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
116 /* Load registered type library */
117 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
118 if (FAILED(hr)) {
119 hr = LoadTypeLib(szMsiServer, &pLib);
120 if (FAILED(hr)) {
121 ERR("Could not load msiserver.tlb\n");
122 return hr;
126 /* Get type information for object */
127 hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
128 ITypeLib_Release(pLib);
129 if (FAILED(hr)) {
130 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
131 return hr;
133 *pptinfo = pInfo;
134 return S_OK;
137 static inline AutomationObject *impl_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
139 return CONTAINING_RECORD(iface, AutomationObject, IProvideMultipleClassInfo_iface);
142 static inline AutomationObject *impl_from_IDispatch( IDispatch *iface )
144 return CONTAINING_RECORD(iface, AutomationObject, IDispatch_iface);
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 SessionImpl_Invoke(
1243 AutomationObject* This,
1244 DISPID dispIdMember,
1245 REFIID riid,
1246 LCID lcid,
1247 WORD wFlags,
1248 DISPPARAMS* pDispParams,
1249 VARIANT* pVarResult,
1250 EXCEPINFO* pExcepInfo,
1251 UINT* puArgErr)
1253 SessionObject *session = (SessionObject*)This;
1254 WCHAR *szString;
1255 DWORD dwLen;
1256 IDispatch *pDispatch = NULL;
1257 MSIHANDLE msiHandle;
1258 LANGID langId;
1259 UINT ret;
1260 INSTALLSTATE iInstalled, iAction;
1261 VARIANTARG varg0, varg1;
1262 HRESULT hr;
1264 VariantInit(&varg0);
1265 VariantInit(&varg1);
1267 switch (dispIdMember)
1269 case DISPID_SESSION_INSTALLER:
1270 if (wFlags & DISPATCH_PROPERTYGET) {
1271 V_VT(pVarResult) = VT_DISPATCH;
1272 IDispatch_AddRef(session->installer);
1273 V_DISPATCH(pVarResult) = session->installer;
1275 else return DISP_E_MEMBERNOTFOUND;
1276 break;
1278 case DISPID_SESSION_PROPERTY:
1279 if (wFlags & DISPATCH_PROPERTYGET) {
1280 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1281 if (FAILED(hr)) return hr;
1282 V_VT(pVarResult) = VT_BSTR;
1283 V_BSTR(pVarResult) = NULL;
1284 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1286 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1287 ERR("Out of memory\n");
1288 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1289 V_BSTR(pVarResult) = SysAllocString(szString);
1290 msi_free(szString);
1292 if (ret != ERROR_SUCCESS)
1293 ERR("MsiGetProperty returned %d\n", ret);
1294 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1295 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1296 if (FAILED(hr)) return hr;
1297 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1298 if (FAILED(hr)) {
1299 VariantClear(&varg0);
1300 return hr;
1302 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1304 VariantClear(&varg0);
1305 VariantClear(&varg1);
1306 ERR("MsiSetProperty returned %d\n", ret);
1307 return DISP_E_EXCEPTION;
1310 else return DISP_E_MEMBERNOTFOUND;
1311 break;
1313 case DISPID_SESSION_LANGUAGE:
1314 if (wFlags & DISPATCH_PROPERTYGET) {
1315 langId = MsiGetLanguage(This->msiHandle);
1316 V_VT(pVarResult) = VT_I4;
1317 V_I4(pVarResult) = langId;
1319 else return DISP_E_MEMBERNOTFOUND;
1320 break;
1322 case DISPID_SESSION_MODE:
1323 if (wFlags & DISPATCH_PROPERTYGET) {
1324 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1325 if (FAILED(hr)) return hr;
1326 V_VT(pVarResult) = VT_BOOL;
1327 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1328 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1329 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1330 if (FAILED(hr)) return hr;
1331 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1332 if (FAILED(hr)) return hr;
1333 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1335 ERR("MsiSetMode returned %d\n", ret);
1336 return DISP_E_EXCEPTION;
1339 else return DISP_E_MEMBERNOTFOUND;
1340 break;
1342 case DISPID_SESSION_DATABASE:
1343 if (wFlags & DISPATCH_PROPERTYGET) {
1344 V_VT(pVarResult) = VT_DISPATCH;
1345 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1347 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1348 V_DISPATCH(pVarResult) = pDispatch;
1349 else
1350 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1352 else
1354 ERR("MsiGetActiveDatabase failed\n");
1355 return DISP_E_EXCEPTION;
1358 else return DISP_E_MEMBERNOTFOUND;
1359 break;
1361 case DISPID_SESSION_DOACTION:
1362 if (wFlags & DISPATCH_METHOD) {
1363 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1364 if (FAILED(hr)) return hr;
1365 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1366 V_VT(pVarResult) = VT_I4;
1367 switch (ret)
1369 case ERROR_FUNCTION_NOT_CALLED:
1370 V_I4(pVarResult) = msiDoActionStatusNoAction;
1371 break;
1372 case ERROR_SUCCESS:
1373 V_I4(pVarResult) = msiDoActionStatusSuccess;
1374 break;
1375 case ERROR_INSTALL_USEREXIT:
1376 V_I4(pVarResult) = msiDoActionStatusUserExit;
1377 break;
1378 case ERROR_INSTALL_FAILURE:
1379 V_I4(pVarResult) = msiDoActionStatusFailure;
1380 break;
1381 case ERROR_INSTALL_SUSPEND:
1382 V_I4(pVarResult) = msiDoActionStatusSuspend;
1383 break;
1384 case ERROR_MORE_DATA:
1385 V_I4(pVarResult) = msiDoActionStatusFinished;
1386 break;
1387 case ERROR_INVALID_HANDLE_STATE:
1388 V_I4(pVarResult) = msiDoActionStatusWrongState;
1389 break;
1390 case ERROR_INVALID_DATA:
1391 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1392 break;
1393 default:
1394 VariantClear(&varg0);
1395 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1396 return DISP_E_EXCEPTION;
1399 else return DISP_E_MEMBERNOTFOUND;
1400 break;
1402 case DISPID_SESSION_EVALUATECONDITION:
1403 if (wFlags & DISPATCH_METHOD) {
1404 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1405 if (FAILED(hr)) return hr;
1406 V_VT(pVarResult) = VT_I4;
1407 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1409 else return DISP_E_MEMBERNOTFOUND;
1410 break;
1412 case DISPID_SESSION_MESSAGE:
1413 if(!(wFlags & DISPATCH_METHOD))
1414 return DISP_E_MEMBERNOTFOUND;
1416 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1417 if (FAILED(hr)) return hr;
1418 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1419 if (FAILED(hr)) return hr;
1421 V_VT(pVarResult) = VT_I4;
1422 V_I4(pVarResult) =
1423 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
1424 break;
1426 case DISPID_SESSION_SETINSTALLLEVEL:
1427 if (wFlags & DISPATCH_METHOD) {
1428 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1429 if (FAILED(hr)) return hr;
1430 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1432 ERR("MsiSetInstallLevel returned %d\n", ret);
1433 return DISP_E_EXCEPTION;
1436 else return DISP_E_MEMBERNOTFOUND;
1437 break;
1439 case DISPID_SESSION_FEATURECURRENTSTATE:
1440 if (wFlags & DISPATCH_PROPERTYGET) {
1441 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1442 if (FAILED(hr)) return hr;
1443 V_VT(pVarResult) = VT_I4;
1444 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1445 V_I4(pVarResult) = iInstalled;
1446 else
1448 ERR("MsiGetFeatureState returned %d\n", ret);
1449 V_I4(pVarResult) = msiInstallStateUnknown;
1452 else return DISP_E_MEMBERNOTFOUND;
1453 break;
1455 case DISPID_SESSION_FEATUREREQUESTSTATE:
1456 if (wFlags & DISPATCH_PROPERTYGET) {
1457 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1458 if (FAILED(hr)) return hr;
1459 V_VT(pVarResult) = VT_I4;
1460 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1461 V_I4(pVarResult) = iAction;
1462 else
1464 ERR("MsiGetFeatureState returned %d\n", ret);
1465 V_I4(pVarResult) = msiInstallStateUnknown;
1467 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1468 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1469 if (FAILED(hr)) return hr;
1470 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1471 if (FAILED(hr)) {
1472 VariantClear(&varg0);
1473 return hr;
1475 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1477 VariantClear(&varg0);
1478 ERR("MsiSetFeatureState returned %d\n", ret);
1479 return DISP_E_EXCEPTION;
1482 else return DISP_E_MEMBERNOTFOUND;
1483 break;
1485 default:
1486 return DISP_E_MEMBERNOTFOUND;
1489 VariantClear(&varg1);
1490 VariantClear(&varg0);
1492 return S_OK;
1495 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1496 * registry value type. Used by Installer::RegistryValue. */
1497 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1499 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1500 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1501 WCHAR *szString = (WCHAR *)lpData;
1502 LPWSTR szNewString = NULL;
1503 DWORD dwNewSize = 0;
1504 int idx;
1506 switch (dwType)
1508 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1509 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1510 idx = (dwSize/sizeof(WCHAR))-1;
1511 while (idx >= 0 && !szString[idx]) idx--;
1512 for (; idx >= 0; idx--)
1513 if (!szString[idx]) szString[idx] = '\n';
1514 /* fall through */
1515 case REG_SZ:
1516 V_VT(pVarResult) = VT_BSTR;
1517 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1518 break;
1520 case REG_EXPAND_SZ:
1521 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1522 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1523 else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1524 ERR("Out of memory\n");
1525 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1526 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1527 else
1529 V_VT(pVarResult) = VT_BSTR;
1530 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1532 msi_free(szNewString);
1533 break;
1535 case REG_DWORD:
1536 V_VT(pVarResult) = VT_I4;
1537 V_I4(pVarResult) = *((DWORD *)lpData);
1538 break;
1540 case REG_QWORD:
1541 V_VT(pVarResult) = VT_BSTR;
1542 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1543 break;
1545 case REG_BINARY:
1546 V_VT(pVarResult) = VT_BSTR;
1547 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1548 break;
1550 case REG_NONE:
1551 V_VT(pVarResult) = VT_EMPTY;
1552 break;
1554 default:
1555 FIXME("Unhandled registry value type %d\n", dwType);
1559 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1560 DISPPARAMS* pDispParams,
1561 VARIANT* pVarResult,
1562 EXCEPINFO* pExcepInfo,
1563 UINT* puArgErr)
1565 HRESULT hr;
1566 VARIANTARG varg0;
1567 MSIHANDLE hrec;
1568 IDispatch* dispatch;
1570 if (!(wFlags & DISPATCH_METHOD))
1571 return DISP_E_MEMBERNOTFOUND;
1573 VariantInit(&varg0);
1574 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1575 if (FAILED(hr))
1576 return hr;
1578 V_VT(pVarResult) = VT_DISPATCH;
1580 hrec = MsiCreateRecord(V_I4(&varg0));
1581 if (!hrec)
1582 return DISP_E_EXCEPTION;
1584 hr = create_automation_object(hrec, NULL, (LPVOID*)&dispatch,
1585 &DIID_Record, RecordImpl_Invoke, NULL, 0);
1586 if (SUCCEEDED(hr))
1587 V_DISPATCH(pVarResult) = dispatch;
1589 return hr;
1592 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1593 WORD wFlags,
1594 DISPPARAMS* pDispParams,
1595 VARIANT* pVarResult,
1596 EXCEPINFO* pExcepInfo,
1597 UINT* puArgErr)
1599 UINT ret;
1600 HRESULT hr;
1601 MSIHANDLE hpkg;
1602 IDispatch* dispatch;
1603 VARIANTARG varg0, varg1;
1605 if (!(wFlags & DISPATCH_METHOD))
1606 return DISP_E_MEMBERNOTFOUND;
1608 if (pDispParams->cArgs == 0)
1609 return DISP_E_TYPEMISMATCH;
1611 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1612 return DISP_E_TYPEMISMATCH;
1614 VariantInit(&varg0);
1615 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1616 if (FAILED(hr))
1617 return hr;
1619 VariantInit(&varg1);
1620 if (pDispParams->cArgs == 2)
1622 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1623 if (FAILED(hr))
1624 goto done;
1626 else
1628 V_VT(&varg1) = VT_I4;
1629 V_I4(&varg1) = 0;
1632 V_VT(pVarResult) = VT_DISPATCH;
1634 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1635 if (ret != ERROR_SUCCESS)
1637 hr = DISP_E_EXCEPTION;
1638 goto done;
1641 hr = create_session(hpkg, &This->IDispatch_iface, &dispatch);
1642 if (SUCCEEDED(hr))
1643 V_DISPATCH(pVarResult) = dispatch;
1645 done:
1646 VariantClear(&varg0);
1647 VariantClear(&varg1);
1648 return hr;
1651 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1652 DISPPARAMS* pDispParams,
1653 VARIANT* pVarResult,
1654 EXCEPINFO* pExcepInfo,
1655 UINT* puArgErr)
1657 HRESULT hr;
1658 VARIANTARG varg0;
1660 if (!(wFlags & DISPATCH_METHOD))
1661 return DISP_E_MEMBERNOTFOUND;
1663 VariantInit(&varg0);
1664 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1665 if (FAILED(hr))
1666 return hr;
1668 FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1670 VariantInit(pVarResult);
1672 VariantClear(&varg0);
1673 return S_OK;
1676 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1677 DISPPARAMS* pDispParams,
1678 VARIANT* pVarResult,
1679 EXCEPINFO* pExcepInfo,
1680 UINT* puArgErr)
1682 UINT ret;
1683 HRESULT hr;
1684 MSIHANDLE hdb;
1685 IDispatch* dispatch;
1686 VARIANTARG varg0, varg1;
1688 if (!(wFlags & DISPATCH_METHOD))
1689 return DISP_E_MEMBERNOTFOUND;
1691 VariantInit(&varg0);
1692 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1693 if (FAILED(hr))
1694 return hr;
1696 VariantInit(&varg1);
1697 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1698 if (FAILED(hr))
1699 goto done;
1701 V_VT(pVarResult) = VT_DISPATCH;
1703 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1704 if (ret != ERROR_SUCCESS)
1706 hr = DISP_E_EXCEPTION;
1707 goto done;
1710 hr = create_automation_object(hdb, NULL, (LPVOID *)&dispatch,
1711 &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1712 if (SUCCEEDED(hr))
1713 V_DISPATCH(pVarResult) = dispatch;
1715 done:
1716 VariantClear(&varg0);
1717 VariantClear(&varg1);
1718 return hr;
1721 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1722 DISPPARAMS* pDispParams,
1723 VARIANT* pVarResult,
1724 EXCEPINFO* pExcepInfo,
1725 UINT* puArgErr)
1727 if (!(wFlags & DISPATCH_METHOD))
1728 return DISP_E_MEMBERNOTFOUND;
1730 FIXME("\n");
1732 VariantInit(pVarResult);
1733 return S_OK;
1736 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1737 DISPPARAMS* pDispParams,
1738 VARIANT* pVarResult,
1739 EXCEPINFO* pExcepInfo,
1740 UINT* puArgErr)
1742 HRESULT hr;
1743 VARIANTARG varg0;
1744 INSTALLUILEVEL ui;
1746 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1747 return DISP_E_MEMBERNOTFOUND;
1749 if (wFlags & DISPATCH_PROPERTYPUT)
1751 VariantInit(&varg0);
1752 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1753 if (FAILED(hr))
1754 return hr;
1756 ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1757 if (ui == INSTALLUILEVEL_NOCHANGE)
1758 return DISP_E_EXCEPTION;
1760 else if (wFlags & DISPATCH_PROPERTYGET)
1762 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1763 if (ui == INSTALLUILEVEL_NOCHANGE)
1764 return DISP_E_EXCEPTION;
1766 V_VT(pVarResult) = VT_I4;
1767 V_I4(pVarResult) = ui;
1770 return S_OK;
1773 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1774 DISPPARAMS* pDispParams,
1775 VARIANT* pVarResult,
1776 EXCEPINFO* pExcepInfo,
1777 UINT* puArgErr)
1779 if (!(wFlags & DISPATCH_METHOD))
1780 return DISP_E_MEMBERNOTFOUND;
1782 FIXME("\n");
1784 VariantInit(pVarResult);
1785 return S_OK;
1788 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1789 DISPPARAMS* pDispParams,
1790 VARIANT* pVarResult,
1791 EXCEPINFO* pExcepInfo,
1792 UINT* puArgErr)
1794 UINT ret;
1795 HRESULT hr;
1796 VARIANTARG varg0, varg1;
1798 if (!(wFlags & DISPATCH_METHOD))
1799 return DISP_E_MEMBERNOTFOUND;
1801 VariantInit(&varg0);
1802 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1803 if (FAILED(hr))
1804 return hr;
1806 VariantInit(&varg1);
1807 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1808 if (FAILED(hr))
1809 goto done;
1811 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1812 if (ret != ERROR_SUCCESS)
1814 hr = DISP_E_EXCEPTION;
1815 goto done;
1818 done:
1819 VariantClear(&varg0);
1820 VariantClear(&varg1);
1821 return hr;
1824 static HRESULT InstallerImpl_Version(WORD wFlags,
1825 VARIANT* pVarResult,
1826 EXCEPINFO* pExcepInfo,
1827 UINT* puArgErr)
1829 HRESULT hr;
1830 DLLVERSIONINFO verinfo;
1831 WCHAR version[MAX_PATH];
1833 static const WCHAR format[] = {
1834 '%','d','.','%','d','.','%','d','.','%','d',0};
1836 if (!(wFlags & DISPATCH_PROPERTYGET))
1837 return DISP_E_MEMBERNOTFOUND;
1839 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1840 hr = DllGetVersion(&verinfo);
1841 if (FAILED(hr))
1842 return hr;
1844 sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1845 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1847 V_VT(pVarResult) = VT_BSTR;
1848 V_BSTR(pVarResult) = SysAllocString(version);
1849 return S_OK;
1852 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1853 DISPPARAMS* pDispParams,
1854 VARIANT* pVarResult,
1855 EXCEPINFO* pExcepInfo,
1856 UINT* puArgErr)
1858 if (!(wFlags & DISPATCH_METHOD))
1859 return DISP_E_MEMBERNOTFOUND;
1861 FIXME("\n");
1863 VariantInit(pVarResult);
1864 return S_OK;
1867 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1868 DISPPARAMS* pDispParams,
1869 VARIANT* pVarResult,
1870 EXCEPINFO* pExcepInfo,
1871 UINT* puArgErr)
1873 UINT ret;
1874 HKEY hkey = NULL;
1875 HRESULT hr;
1876 UINT posValue;
1877 DWORD type, size;
1878 LPWSTR szString = NULL;
1879 VARIANTARG varg0, varg1, varg2;
1881 if (!(wFlags & DISPATCH_METHOD))
1882 return DISP_E_MEMBERNOTFOUND;
1884 VariantInit(&varg0);
1885 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1886 if (FAILED(hr))
1887 return hr;
1889 VariantInit(&varg1);
1890 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1891 if (FAILED(hr))
1892 goto done;
1894 /* Save valuePos so we can save puArgErr if we are unable to do our type
1895 * conversions.
1897 posValue = 2;
1898 VariantInit(&varg2);
1899 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1900 if (FAILED(hr))
1901 goto done;
1903 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
1904 V_I4(&varg0) <= REG_INDEX_DYN_DATA)
1906 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
1909 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1911 /* Only VT_EMPTY case can do anything if the key doesn't exist. */
1912 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
1914 hr = DISP_E_BADINDEX;
1915 goto done;
1918 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1919 switch (V_VT(&varg2))
1921 /* Return VT_BOOL clarifying whether registry key exists or not. */
1922 case VT_EMPTY:
1923 V_VT(pVarResult) = VT_BOOL;
1924 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1925 break;
1927 /* Return the value of specified key if it exists. */
1928 case VT_BSTR:
1929 ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
1930 NULL, NULL, NULL, &size);
1931 if (ret != ERROR_SUCCESS)
1933 hr = DISP_E_BADINDEX;
1934 goto done;
1937 szString = msi_alloc(size);
1938 if (!szString)
1940 hr = E_OUTOFMEMORY;
1941 goto done;
1944 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
1945 &type, (LPBYTE)szString, &size);
1946 if (ret != ERROR_SUCCESS)
1948 msi_free(szString);
1949 hr = DISP_E_BADINDEX;
1950 goto done;
1953 variant_from_registry_value(pVarResult, type,
1954 (LPBYTE)szString, size);
1955 msi_free(szString);
1956 break;
1958 /* Try to make it into VT_I4, can use VariantChangeType for this. */
1959 default:
1960 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1961 if (FAILED(hr))
1963 if (hr == DISP_E_TYPEMISMATCH)
1964 *puArgErr = posValue;
1966 goto done;
1969 /* Retrieve class name or maximum value name or subkey name size. */
1970 if (!V_I4(&varg2))
1971 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
1972 NULL, NULL, NULL, NULL, NULL, NULL);
1973 else if (V_I4(&varg2) > 0)
1974 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
1975 NULL, NULL, &size, NULL, NULL, NULL);
1976 else /* V_I4(&varg2) < 0 */
1977 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
1978 NULL, NULL, NULL, NULL, NULL, NULL);
1980 if (ret != ERROR_SUCCESS)
1981 goto done;
1983 szString = msi_alloc(++size * sizeof(WCHAR));
1984 if (!szString)
1986 hr = E_OUTOFMEMORY;
1987 goto done;
1990 if (!V_I4(&varg2))
1991 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
1992 NULL, NULL, NULL, NULL, NULL, NULL);
1993 else if (V_I4(&varg2) > 0)
1994 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
1995 &size, 0, 0, NULL, NULL);
1996 else /* V_I4(&varg2) < 0 */
1997 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
1999 if (ret == ERROR_SUCCESS)
2001 V_VT(pVarResult) = VT_BSTR;
2002 V_BSTR(pVarResult) = SysAllocString(szString);
2005 msi_free(szString);
2008 done:
2009 VariantClear(&varg0);
2010 VariantClear(&varg1);
2011 VariantClear(&varg2);
2012 RegCloseKey(hkey);
2013 return hr;
2016 static HRESULT InstallerImpl_Environment(WORD wFlags,
2017 DISPPARAMS* pDispParams,
2018 VARIANT* pVarResult,
2019 EXCEPINFO* pExcepInfo,
2020 UINT* puArgErr)
2022 if (!(wFlags & DISPATCH_METHOD))
2023 return DISP_E_MEMBERNOTFOUND;
2025 FIXME("\n");
2027 VariantInit(pVarResult);
2028 return S_OK;
2031 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2032 DISPPARAMS* pDispParams,
2033 VARIANT* pVarResult,
2034 EXCEPINFO* pExcepInfo,
2035 UINT* puArgErr)
2037 if (!(wFlags & DISPATCH_METHOD))
2038 return DISP_E_MEMBERNOTFOUND;
2040 FIXME("\n");
2042 VariantInit(pVarResult);
2043 return S_OK;
2046 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2047 DISPPARAMS* pDispParams,
2048 VARIANT* pVarResult,
2049 EXCEPINFO* pExcepInfo,
2050 UINT* puArgErr)
2052 if (!(wFlags & DISPATCH_METHOD))
2053 return DISP_E_MEMBERNOTFOUND;
2055 FIXME("\n");
2057 VariantInit(pVarResult);
2058 return S_OK;
2061 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2062 DISPPARAMS* pDispParams,
2063 VARIANT* pVarResult,
2064 EXCEPINFO* pExcepInfo,
2065 UINT* puArgErr)
2067 if (!(wFlags & DISPATCH_METHOD))
2068 return DISP_E_MEMBERNOTFOUND;
2070 FIXME("\n");
2072 VariantInit(pVarResult);
2073 return S_OK;
2076 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2077 DISPPARAMS* pDispParams,
2078 VARIANT* pVarResult,
2079 EXCEPINFO* pExcepInfo,
2080 UINT* puArgErr)
2082 HRESULT hr;
2083 VARIANTARG varg0;
2085 if (!(wFlags & DISPATCH_PROPERTYGET))
2086 return DISP_E_MEMBERNOTFOUND;
2088 VariantInit(&varg0);
2089 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2090 if (FAILED(hr))
2091 return hr;
2093 V_VT(pVarResult) = VT_I4;
2094 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2096 VariantClear(&varg0);
2097 return S_OK;
2100 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2101 DISPPARAMS* pDispParams,
2102 VARIANT* pVarResult,
2103 EXCEPINFO* pExcepInfo,
2104 UINT* puArgErr)
2106 UINT ret;
2107 HRESULT hr;
2108 DWORD size;
2109 LPWSTR str = NULL;
2110 VARIANTARG varg0, varg1;
2112 if (!(wFlags & DISPATCH_PROPERTYGET))
2113 return DISP_E_MEMBERNOTFOUND;
2115 VariantInit(&varg0);
2116 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2117 if (FAILED(hr))
2118 return hr;
2120 VariantInit(&varg1);
2121 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2122 if (FAILED(hr))
2123 goto done;
2125 V_VT(pVarResult) = VT_BSTR;
2126 V_BSTR(pVarResult) = NULL;
2128 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2129 if (ret != ERROR_SUCCESS)
2131 hr = DISP_E_EXCEPTION;
2132 goto done;
2135 str = msi_alloc(++size * sizeof(WCHAR));
2136 if (!str)
2138 hr = E_OUTOFMEMORY;
2139 goto done;
2142 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2143 if (ret != ERROR_SUCCESS)
2145 hr = DISP_E_EXCEPTION;
2146 goto done;
2149 V_BSTR(pVarResult) = SysAllocString(str);
2150 hr = S_OK;
2152 done:
2153 msi_free(str);
2154 VariantClear(&varg0);
2155 VariantClear(&varg1);
2156 return hr;
2159 static void cleanup_products(IDispatch* dispatch, ULONG count)
2161 UINT i;
2162 ListData* ldata = private_data((AutomationObject *)dispatch);
2164 for (i = 0; i < count - 1; i++)
2165 VariantClear(&ldata->pVars[i]);
2167 ldata->ulCount = 0;
2168 msi_free(ldata->pVars);
2170 IDispatch_Release(dispatch);
2173 static HRESULT InstallerImpl_Products(WORD wFlags,
2174 DISPPARAMS* pDispParams,
2175 VARIANT* pVarResult,
2176 EXCEPINFO* pExcepInfo,
2177 UINT* puArgErr)
2179 UINT ret;
2180 HRESULT hr;
2181 ULONG idx = 0;
2182 ListData *ldata;
2183 IDispatch *dispatch;
2184 WCHAR product[GUID_SIZE];
2186 if (!(wFlags & DISPATCH_PROPERTYGET))
2187 return DISP_E_MEMBERNOTFOUND;
2189 /* Find number of products. */
2190 while ((ret = MsiEnumProductsW(idx, product)) == ERROR_SUCCESS)
2191 idx++;
2193 if (ret != ERROR_NO_MORE_ITEMS)
2194 return DISP_E_EXCEPTION;
2196 V_VT(pVarResult) = VT_DISPATCH;
2197 hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2198 &DIID_StringList, ListImpl_Invoke,
2199 ListImpl_Free, sizeof(ListData));
2200 if (FAILED(hr))
2201 return hr;
2203 V_DISPATCH(pVarResult) = dispatch;
2205 /* Save product strings. */
2206 ldata = private_data((AutomationObject *)dispatch);
2207 ldata->ulCount = 0;
2208 ldata->pVars = msi_alloc_zero(sizeof(VARIANT) * idx);
2209 if (!ldata->pVars)
2211 IDispatch_Release(dispatch);
2212 return E_OUTOFMEMORY;
2215 ldata->ulCount = idx;
2216 for (idx = 0; idx < ldata->ulCount; idx++)
2218 ret = MsiEnumProductsW(idx, product);
2219 if (ret != ERROR_SUCCESS)
2221 cleanup_products(dispatch, idx - 1);
2222 return DISP_E_EXCEPTION;
2225 VariantInit(&ldata->pVars[idx]);
2226 V_VT(&ldata->pVars[idx]) = VT_BSTR;
2227 V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2230 return S_OK;
2233 static HRESULT InstallerImpl_RelatedProducts(WORD wFlags,
2234 DISPPARAMS* pDispParams,
2235 VARIANT* pVarResult,
2236 EXCEPINFO* pExcepInfo,
2237 UINT* puArgErr)
2239 UINT ret;
2240 ULONG idx;
2241 HRESULT hr;
2242 ListData *ldata;
2243 VARIANTARG varg0;
2244 IDispatch* dispatch;
2245 WCHAR product[GUID_SIZE];
2247 if (!(wFlags & DISPATCH_PROPERTYGET))
2248 return DISP_E_MEMBERNOTFOUND;
2250 VariantInit(&varg0);
2251 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2252 if (FAILED(hr))
2253 return hr;
2255 /* Find number of related products. */
2256 idx = 0;
2259 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2260 if (ret == ERROR_SUCCESS)
2261 idx++;
2262 } while (ret == ERROR_SUCCESS);
2264 if (ret != ERROR_NO_MORE_ITEMS)
2266 hr = DISP_E_EXCEPTION;
2267 goto done;
2270 V_VT(pVarResult) = VT_DISPATCH;
2272 hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2273 &DIID_StringList, ListImpl_Invoke,
2274 ListImpl_Free, sizeof(ListData));
2275 if (FAILED(hr))
2276 goto done;
2278 V_DISPATCH(pVarResult) = dispatch;
2280 /* Save product strings. */
2281 ldata = private_data((AutomationObject *)dispatch);
2282 ldata->pVars = msi_alloc(sizeof(VARIANT) * idx);
2283 if (!ldata->pVars)
2285 IDispatch_Release(dispatch);
2286 hr = E_OUTOFMEMORY;
2287 goto done;
2290 ldata->ulCount = idx;
2291 for (idx = 0; idx < ldata->ulCount; idx++)
2293 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2294 if (ret != ERROR_SUCCESS)
2296 cleanup_products(dispatch, idx - 1);
2297 hr = DISP_E_EXCEPTION;
2298 goto done;
2301 VariantInit(&ldata->pVars[idx]);
2302 V_VT(&ldata->pVars[idx]) = VT_BSTR;
2303 V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2306 hr = S_OK;
2308 done:
2309 VariantClear(&varg0);
2310 return hr;
2313 static HRESULT InstallerImpl_Invoke(
2314 AutomationObject* This,
2315 DISPID dispIdMember,
2316 REFIID riid,
2317 LCID lcid,
2318 WORD wFlags,
2319 DISPPARAMS* pDispParams,
2320 VARIANT* pVarResult,
2321 EXCEPINFO* pExcepInfo,
2322 UINT* puArgErr)
2324 switch (dispIdMember)
2326 case DISPID_INSTALLER_CREATERECORD:
2327 return InstallerImpl_CreateRecord(wFlags, pDispParams,
2328 pVarResult, pExcepInfo, puArgErr);
2330 case DISPID_INSTALLER_OPENPACKAGE:
2331 return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2332 pVarResult, pExcepInfo, puArgErr);
2334 case DISPID_INSTALLER_OPENPRODUCT:
2335 return InstallerImpl_OpenProduct(wFlags, pDispParams,
2336 pVarResult, pExcepInfo, puArgErr);
2338 case DISPID_INSTALLER_OPENDATABASE:
2339 return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2340 pVarResult, pExcepInfo, puArgErr);
2342 case DISPID_INSTALLER_SUMMARYINFORMATION:
2343 return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2344 pVarResult, pExcepInfo,
2345 puArgErr);
2347 case DISPID_INSTALLER_UILEVEL:
2348 return InstallerImpl_UILevel(wFlags, pDispParams,
2349 pVarResult, pExcepInfo, puArgErr);
2351 case DISPID_INSTALLER_ENABLELOG:
2352 return InstallerImpl_EnableLog(wFlags, pDispParams,
2353 pVarResult, pExcepInfo, puArgErr);
2355 case DISPID_INSTALLER_INSTALLPRODUCT:
2356 return InstallerImpl_InstallProduct(wFlags, pDispParams,
2357 pVarResult, pExcepInfo,
2358 puArgErr);
2360 case DISPID_INSTALLER_VERSION:
2361 return InstallerImpl_Version(wFlags, pVarResult,
2362 pExcepInfo, puArgErr);
2364 case DISPID_INSTALLER_LASTERRORRECORD:
2365 return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2366 pVarResult, pExcepInfo,
2367 puArgErr);
2369 case DISPID_INSTALLER_REGISTRYVALUE:
2370 return InstallerImpl_RegistryValue(wFlags, pDispParams,
2371 pVarResult, pExcepInfo,
2372 puArgErr);
2374 case DISPID_INSTALLER_ENVIRONMENT:
2375 return InstallerImpl_Environment(wFlags, pDispParams,
2376 pVarResult, pExcepInfo, puArgErr);
2378 case DISPID_INSTALLER_FILEATTRIBUTES:
2379 return InstallerImpl_FileAttributes(wFlags, pDispParams,
2380 pVarResult, pExcepInfo,
2381 puArgErr);
2383 case DISPID_INSTALLER_FILESIZE:
2384 return InstallerImpl_FileSize(wFlags, pDispParams,
2385 pVarResult, pExcepInfo, puArgErr);
2387 case DISPID_INSTALLER_FILEVERSION:
2388 return InstallerImpl_FileVersion(wFlags, pDispParams,
2389 pVarResult, pExcepInfo, puArgErr);
2391 case DISPID_INSTALLER_PRODUCTSTATE:
2392 return InstallerImpl_ProductState(wFlags, pDispParams,
2393 pVarResult, pExcepInfo, puArgErr);
2395 case DISPID_INSTALLER_PRODUCTINFO:
2396 return InstallerImpl_ProductInfo(wFlags, pDispParams,
2397 pVarResult, pExcepInfo, puArgErr);
2399 case DISPID_INSTALLER_PRODUCTS:
2400 return InstallerImpl_Products(wFlags, pDispParams,
2401 pVarResult, pExcepInfo, puArgErr);
2403 case DISPID_INSTALLER_RELATEDPRODUCTS:
2404 return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2405 pVarResult, pExcepInfo,
2406 puArgErr);
2408 default:
2409 return DISP_E_MEMBERNOTFOUND;
2413 /* Wrapper around create_automation_object to create an installer object. */
2414 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
2416 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
2419 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp)
2421 SessionObject *session;
2422 HRESULT hr;
2424 session = msi_alloc(sizeof(SessionObject));
2425 if (!session) return E_OUTOFMEMORY;
2427 hr = init_automation_object(&session->autoobj, msiHandle, &DIID_Session, SessionImpl_Invoke, NULL);
2428 if (hr != S_OK)
2430 msi_free(session);
2431 return hr;
2434 session->installer = installer;
2435 *disp = &session->autoobj.IDispatch_iface;
2437 return hr;