msi: automation: Implement Record::FieldCount.
[wine/multimedia.git] / dlls / msi / automation.c
blobe314be06729e07d91766d3f08ddae9bd43b86b32
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 "wine/debug.h"
34 #include "wine/unicode.h"
36 #include "msiserver.h"
37 #include "msiserver_dispids.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
43 * called from AutomationObject::Invoke, and pass this function to create_automation_object.
46 typedef interface AutomationObject AutomationObject;
48 interface AutomationObject {
50 * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
52 const IDispatchVtbl *lpVtbl;
53 const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
55 /* Object reference count */
56 LONG ref;
58 /* Clsid for this class and it's appropriate ITypeInfo object */
59 LPCLSID clsid;
60 ITypeInfo *iTypeInfo;
62 /* The MSI handle of the current object */
63 MSIHANDLE msiHandle;
65 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
66 HRESULT (STDMETHODCALLTYPE *funcInvoke)(
67 AutomationObject* This,
68 DISPID dispIdMember,
69 REFIID riid,
70 LCID lcid,
71 WORD wFlags,
72 DISPPARAMS* pDispParams,
73 VARIANT* pVarResult,
74 EXCEPINFO* pExcepInfo,
75 UINT* puArgErr);
77 /* A function that is called from AutomationObject::Release when the object is being freed to free any private
78 * data structures (or NULL) */
79 void (STDMETHODCALLTYPE *funcFree)(AutomationObject* This);
83 * Structures for additional data required by specific automation objects
86 typedef struct {
87 int iCount;
88 LPWSTR *pszStrings;
89 } StringListData;
91 typedef struct {
92 /* The parent Installer object */
93 IDispatch *pInstaller;
94 } SessionData;
96 /* VTables */
97 static const struct IDispatchVtbl AutomationObject_Vtbl;
98 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
100 /* Load type info so we don't have to process GetIDsOfNames */
101 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
103 HRESULT hr;
104 LPTYPELIB pLib = NULL;
105 LPTYPEINFO pInfo = NULL;
106 static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
108 TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
110 /* Load registered type library */
111 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
112 if (FAILED(hr)) {
113 hr = LoadTypeLib(szMsiServer, &pLib);
114 if (FAILED(hr)) {
115 ERR("Could not load msiserver.tlb\n");
116 return hr;
120 /* Get type information for object */
121 hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
122 ITypeLib_Release(pLib);
123 if (FAILED(hr)) {
124 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
125 return hr;
127 *pptinfo = pInfo;
128 return S_OK;
131 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
132 * with the appropriate clsid and invocation function. */
133 HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
134 HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
135 VARIANT*,EXCEPINFO*,UINT*),
136 void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
137 SIZE_T sizetPrivateData)
139 AutomationObject *object;
140 HRESULT hr;
142 TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
144 if( pUnkOuter )
145 return CLASS_E_NOAGGREGATION;
147 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData);
149 /* Set all the VTable references */
150 object->lpVtbl = &AutomationObject_Vtbl;
151 object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
152 object->ref = 1;
154 /* Store data that was passed */
155 object->msiHandle = msiHandle;
156 object->clsid = (LPCLSID)clsid;
157 object->funcInvoke = funcInvoke;
158 object->funcFree = funcFree;
160 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
161 object->iTypeInfo = NULL;
162 hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
163 if (FAILED(hr)) {
164 HeapFree(GetProcessHeap(), 0, object);
165 return hr;
168 *ppObj = object;
170 return S_OK;
173 /* Macros to get pointer to AutomationObject from the other VTables. */
174 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
176 return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
179 /* Macro to get pointer to private object data */
180 static inline void *private_data( AutomationObject *This )
182 return This + 1;
186 * AutomationObject methods
189 /*** IUnknown methods ***/
190 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
192 AutomationObject *This = (AutomationObject *)iface;
194 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
196 if (ppvObject == NULL)
197 return E_INVALIDARG;
199 *ppvObject = 0;
201 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
202 *ppvObject = This;
203 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
204 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
205 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
206 *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
207 else
209 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
210 return E_NOINTERFACE;
214 * Query Interface always increases the reference count by one when it is
215 * successful
217 IClassFactory_AddRef(iface);
219 return S_OK;
222 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
224 AutomationObject *This = (AutomationObject *)iface;
226 TRACE("(%p/%p)\n", iface, This);
228 return InterlockedIncrement(&This->ref);
231 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
233 AutomationObject *This = (AutomationObject *)iface;
234 ULONG ref = InterlockedDecrement(&This->ref);
236 TRACE("(%p/%p)\n", iface, This);
238 if (!ref)
240 if (This->funcFree) This->funcFree(This);
241 MsiCloseHandle(This->msiHandle);
242 HeapFree(GetProcessHeap(), 0, This);
245 return ref;
248 /*** IDispatch methods ***/
249 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
250 IDispatch* iface,
251 UINT* pctinfo)
253 AutomationObject *This = (AutomationObject *)iface;
255 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
256 *pctinfo = 1;
257 return S_OK;
260 static HRESULT WINAPI AutomationObject_GetTypeInfo(
261 IDispatch* iface,
262 UINT iTInfo,
263 LCID lcid,
264 ITypeInfo** ppTInfo)
266 AutomationObject *This = (AutomationObject *)iface;
267 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
269 ITypeInfo_AddRef(This->iTypeInfo);
270 *ppTInfo = This->iTypeInfo;
271 return S_OK;
274 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
275 IDispatch* iface,
276 REFIID riid,
277 LPOLESTR* rgszNames,
278 UINT cNames,
279 LCID lcid,
280 DISPID* rgDispId)
282 AutomationObject *This = (AutomationObject *)iface;
283 HRESULT hr;
284 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
286 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
287 hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
288 if (hr == DISP_E_UNKNOWNNAME)
290 int idx;
291 for (idx=0; idx<cNames; idx++)
293 if (rgDispId[idx] == DISPID_UNKNOWN)
294 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
297 return hr;
300 /* Maximum number of allowed function parameters+1 */
301 #define MAX_FUNC_PARAMS 20
303 /* Some error checking is done here to simplify individual object function invocation */
304 static HRESULT WINAPI AutomationObject_Invoke(
305 IDispatch* iface,
306 DISPID dispIdMember,
307 REFIID riid,
308 LCID lcid,
309 WORD wFlags,
310 DISPPARAMS* pDispParams,
311 VARIANT* pVarResult,
312 EXCEPINFO* pExcepInfo,
313 UINT* puArgErr)
315 AutomationObject *This = (AutomationObject *)iface;
316 HRESULT hr;
317 unsigned int uArgErr;
318 VARIANT varResultDummy;
319 BSTR bstrName = NULL;
321 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
323 if (!IsEqualIID(riid, &IID_NULL))
325 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
326 return DISP_E_UNKNOWNNAME;
329 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
331 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
332 return DISP_E_PARAMNOTOPTIONAL;
335 /* This simplifies our individual object invocation functions */
336 if (puArgErr == NULL) puArgErr = &uArgErr;
337 if (pVarResult == NULL) pVarResult = &varResultDummy;
339 /* Assume return type is void unless determined otherwise */
340 VariantInit(pVarResult);
342 /* If we are tracing, we want to see the name of the member we are invoking */
343 if (TRACE_ON(msi))
345 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
346 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
349 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
351 if (hr == DISP_E_MEMBERNOTFOUND) {
352 if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
353 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
355 else if (pExcepInfo &&
356 (hr == DISP_E_PARAMNOTFOUND ||
357 hr == DISP_E_EXCEPTION)) {
358 static const WCHAR szComma[] = { ',',0 };
359 static WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
360 WCHAR szExceptionDescription[MAX_PATH];
361 BSTR bstrParamNames[MAX_FUNC_PARAMS];
362 unsigned namesNo, i;
363 BOOL bFirst = TRUE;
365 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
366 MAX_FUNC_PARAMS, &namesNo)))
368 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
370 else
372 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
373 for (i=0; i<namesNo; i++)
375 if (bFirst) bFirst = FALSE;
376 else {
377 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
379 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
380 SysFreeString(bstrParamNames[i]);
383 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
384 pExcepInfo->wCode = 1000;
385 pExcepInfo->bstrSource = szExceptionSource;
386 pExcepInfo->bstrDescription = szExceptionDescription;
387 hr = DISP_E_EXCEPTION;
391 /* Make sure we free the return variant if it is our dummy variant */
392 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
394 /* Free function name if we retrieved it */
395 if (bstrName) SysFreeString(bstrName);
397 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
399 return hr;
402 static const struct IDispatchVtbl AutomationObject_Vtbl =
404 AutomationObject_QueryInterface,
405 AutomationObject_AddRef,
406 AutomationObject_Release,
407 AutomationObject_GetTypeInfoCount,
408 AutomationObject_GetTypeInfo,
409 AutomationObject_GetIDsOfNames,
410 AutomationObject_Invoke
414 * IProvideMultipleClassInfo methods
417 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
418 IProvideMultipleClassInfo* iface,
419 REFIID riid,
420 VOID** ppvoid)
422 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
423 return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
426 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
428 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
429 return AutomationObject_AddRef((IDispatch *)This);
432 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
434 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
435 return AutomationObject_Release((IDispatch *)This);
438 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
440 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
441 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
442 return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
445 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
447 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
448 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
450 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
451 return E_INVALIDARG;
452 else {
453 *pGUID = *This->clsid;
454 return S_OK;
458 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
460 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
462 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
463 *pcti = 1;
464 return S_OK;
467 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
468 ULONG iti,
469 DWORD dwFlags,
470 ITypeInfo** pptiCoClass,
471 DWORD* pdwTIFlags,
472 ULONG* pcdispidReserved,
473 IID* piidPrimary,
474 IID* piidSource)
476 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
478 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
480 if (iti != 0)
481 return E_INVALIDARG;
483 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
484 load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
486 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
488 *pdwTIFlags = 0;
489 *pcdispidReserved = 0;
492 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
493 *piidPrimary = *This->clsid;
496 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
497 *piidSource = *This->clsid;
500 return S_OK;
503 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
505 AutomationObject_IProvideMultipleClassInfo_QueryInterface,
506 AutomationObject_IProvideMultipleClassInfo_AddRef,
507 AutomationObject_IProvideMultipleClassInfo_Release,
508 AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
509 AutomationObject_IProvideMultipleClassInfo_GetGUID,
510 AutomationObject_GetMultiTypeInfoCount,
511 AutomationObject_GetInfoOfIndex
515 * Individual Object Invocation Functions
518 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
519 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
520 using DispGetParam/VariantChangeType. */
521 HRESULT WINAPI DispGetParam_CopyOnly(
522 DISPPARAMS *pdispparams, /* [in] Parameter list */
523 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
524 VARIANT *pvarResult) /* [out] Destination for resulting variant */
526 /* position is counted backwards */
527 UINT pos;
529 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
530 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
531 if (*position < pdispparams->cArgs) {
532 /* positional arg? */
533 pos = pdispparams->cArgs - *position - 1;
534 } else {
535 /* FIXME: is this how to handle named args? */
536 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
537 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
539 if (pos==pdispparams->cNamedArgs)
540 return DISP_E_PARAMNOTFOUND;
542 *position = pos;
543 return VariantCopyInd(pvarResult,
544 &pdispparams->rgvarg[pos]);
547 static HRESULT WINAPI RecordImpl_Invoke(
548 AutomationObject* This,
549 DISPID dispIdMember,
550 REFIID riid,
551 LCID lcid,
552 WORD wFlags,
553 DISPPARAMS* pDispParams,
554 VARIANT* pVarResult,
555 EXCEPINFO* pExcepInfo,
556 UINT* puArgErr)
558 WCHAR *szString;
559 DWORD dwLen;
560 UINT ret;
561 VARIANTARG varg0, varg1;
562 HRESULT hr;
564 VariantInit(&varg0);
565 VariantInit(&varg1);
567 switch (dispIdMember)
569 case DISPID_RECORD_FIELDCOUNT:
570 if (wFlags & DISPATCH_PROPERTYGET) {
571 V_VT(pVarResult) = VT_I4;
572 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
574 else return DISP_E_MEMBERNOTFOUND;
575 break;
577 case DISPID_RECORD_STRINGDATA:
578 if (wFlags & DISPATCH_PROPERTYGET) {
579 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
580 if (FAILED(hr)) return hr;
581 V_VT(pVarResult) = VT_BSTR;
582 V_BSTR(pVarResult) = NULL;
583 ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen);
584 if (ret == ERROR_SUCCESS)
586 szString = msi_alloc((++dwLen)*sizeof(WCHAR));
587 if (szString)
589 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
590 V_BSTR(pVarResult) = SysAllocString(szString);
591 msi_free(szString);
594 if (ret != ERROR_SUCCESS)
595 ERR("MsiRecordGetString returned %d\n", ret);
596 } else if (wFlags & DISPATCH_PROPERTYPUT) {
597 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
598 if (FAILED(hr)) return hr;
599 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
600 if (FAILED(hr)) return hr;
601 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
603 VariantClear(&varg1);
604 ERR("MsiRecordSetString returned %d\n", ret);
605 return DISP_E_EXCEPTION;
608 else return DISP_E_MEMBERNOTFOUND;
609 break;
611 default:
612 return DISP_E_MEMBERNOTFOUND;
615 VariantClear(&varg1);
616 VariantClear(&varg0);
618 return S_OK;
621 static HRESULT WINAPI StringListImpl_Invoke(
622 AutomationObject* This,
623 DISPID dispIdMember,
624 REFIID riid,
625 LCID lcid,
626 WORD wFlags,
627 DISPPARAMS* pDispParams,
628 VARIANT* pVarResult,
629 EXCEPINFO* pExcepInfo,
630 UINT* puArgErr)
632 StringListData *data = (StringListData *)private_data(This);
633 HRESULT hr;
634 VARIANTARG varg0;
636 VariantInit(&varg0);
638 switch (dispIdMember)
640 case DISPID_STRINGLIST_ITEM:
641 if (wFlags & DISPATCH_PROPERTYGET) {
642 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
643 if (FAILED(hr)) return hr;
644 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->iCount)
645 return DISP_E_BADINDEX;
646 V_VT(pVarResult) = VT_BSTR;
647 V_BSTR(pVarResult) = SysAllocString(data->pszStrings[V_I4(&varg0)]);
649 else return DISP_E_MEMBERNOTFOUND;
650 break;
652 case DISPID_STRINGLIST_COUNT:
653 if (wFlags & DISPATCH_PROPERTYGET) {
654 V_VT(pVarResult) = VT_I4;
655 V_I4(pVarResult) = data->iCount;
657 else return DISP_E_MEMBERNOTFOUND;
658 break;
660 default:
661 return DISP_E_MEMBERNOTFOUND;
664 VariantClear(&varg0);
666 return S_OK;
669 static void WINAPI StringListImpl_Free(AutomationObject *This)
671 StringListData *data = private_data(This);
672 int idx;
674 for (idx=0; idx<data->iCount; idx++)
675 SysFreeString(data->pszStrings[idx]);
676 HeapFree(GetProcessHeap(), 0, data->pszStrings);
679 static HRESULT WINAPI ViewImpl_Invoke(
680 AutomationObject* This,
681 DISPID dispIdMember,
682 REFIID riid,
683 LCID lcid,
684 WORD wFlags,
685 DISPPARAMS* pDispParams,
686 VARIANT* pVarResult,
687 EXCEPINFO* pExcepInfo,
688 UINT* puArgErr)
690 MSIHANDLE msiHandle;
691 IDispatch *pDispatch = NULL;
692 UINT ret;
693 VARIANTARG varg0, varg1;
694 HRESULT hr;
696 VariantInit(&varg0);
697 VariantInit(&varg1);
699 switch (dispIdMember)
701 case DISPID_VIEW_EXECUTE:
702 if (wFlags & DISPATCH_METHOD)
704 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
705 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
706 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
707 else
708 MsiViewExecute(This->msiHandle, 0);
710 else return DISP_E_MEMBERNOTFOUND;
711 break;
713 case DISPID_VIEW_FETCH:
714 if (wFlags & DISPATCH_METHOD)
716 V_VT(pVarResult) = VT_DISPATCH;
717 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
719 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
721 IDispatch_AddRef(pDispatch);
722 V_DISPATCH(pVarResult) = pDispatch;
724 else
725 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
727 else if (ret == ERROR_NO_MORE_ITEMS)
728 V_DISPATCH(pVarResult) = NULL;
729 else
731 ERR("MsiViewFetch returned %d\n", ret);
732 return DISP_E_EXCEPTION;
735 else return DISP_E_MEMBERNOTFOUND;
736 break;
738 case DISPID_VIEW_CLOSE:
739 if (wFlags & DISPATCH_METHOD)
741 MsiViewClose(This->msiHandle);
743 else return DISP_E_MEMBERNOTFOUND;
744 break;
746 default:
747 return DISP_E_MEMBERNOTFOUND;
750 VariantClear(&varg1);
751 VariantClear(&varg0);
753 return S_OK;
756 static HRESULT WINAPI DatabaseImpl_Invoke(
757 AutomationObject* This,
758 DISPID dispIdMember,
759 REFIID riid,
760 LCID lcid,
761 WORD wFlags,
762 DISPPARAMS* pDispParams,
763 VARIANT* pVarResult,
764 EXCEPINFO* pExcepInfo,
765 UINT* puArgErr)
767 MSIHANDLE msiHandle;
768 IDispatch *pDispatch = NULL;
769 UINT ret;
770 VARIANTARG varg0, varg1;
771 HRESULT hr;
773 VariantInit(&varg0);
774 VariantInit(&varg1);
776 switch (dispIdMember)
778 case DISPID_DATABASE_OPENVIEW:
779 if (wFlags & DISPATCH_METHOD)
781 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
782 if (FAILED(hr)) return hr;
783 V_VT(pVarResult) = VT_DISPATCH;
784 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
786 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
788 IDispatch_AddRef(pDispatch);
789 V_DISPATCH(pVarResult) = pDispatch;
791 else
792 ERR("Failed to create View object, hresult 0x%08x\n", hr);
794 else
796 VariantClear(&varg0);
797 ERR("MsiDatabaseOpenView returned %d\n", ret);
798 return DISP_E_EXCEPTION;
801 else return DISP_E_MEMBERNOTFOUND;
802 break;
804 default:
805 return DISP_E_MEMBERNOTFOUND;
808 VariantClear(&varg1);
809 VariantClear(&varg0);
811 return S_OK;
814 static HRESULT WINAPI SessionImpl_Invoke(
815 AutomationObject* This,
816 DISPID dispIdMember,
817 REFIID riid,
818 LCID lcid,
819 WORD wFlags,
820 DISPPARAMS* pDispParams,
821 VARIANT* pVarResult,
822 EXCEPINFO* pExcepInfo,
823 UINT* puArgErr)
825 SessionData *data = private_data(This);
826 WCHAR *szString;
827 DWORD dwLen;
828 IDispatch *pDispatch = NULL;
829 MSIHANDLE msiHandle;
830 LANGID langId;
831 UINT ret;
832 INSTALLSTATE iInstalled, iAction;
833 VARIANTARG varg0, varg1;
834 HRESULT hr;
836 VariantInit(&varg0);
837 VariantInit(&varg1);
839 switch (dispIdMember)
841 case DISPID_SESSION_INSTALLER:
842 if (wFlags & DISPATCH_PROPERTYGET) {
843 V_VT(pVarResult) = VT_DISPATCH;
844 IDispatch_AddRef(data->pInstaller);
845 V_DISPATCH(pVarResult) = data->pInstaller;
847 else return DISP_E_MEMBERNOTFOUND;
848 break;
850 case DISPID_SESSION_PROPERTY:
851 if (wFlags & DISPATCH_PROPERTYGET) {
852 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
853 if (FAILED(hr)) return hr;
854 V_VT(pVarResult) = VT_BSTR;
855 V_BSTR(pVarResult) = NULL;
856 ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen);
857 if (ret == ERROR_SUCCESS)
859 szString = msi_alloc((++dwLen)*sizeof(WCHAR));
860 if (szString)
862 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
863 V_BSTR(pVarResult) = SysAllocString(szString);
864 msi_free(szString);
867 if (ret != ERROR_SUCCESS)
868 ERR("MsiGetProperty returned %d\n", ret);
869 } else if (wFlags & DISPATCH_PROPERTYPUT) {
870 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
871 if (FAILED(hr)) return hr;
872 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
873 if (FAILED(hr)) {
874 VariantClear(&varg0);
875 return hr;
877 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
879 VariantClear(&varg0);
880 VariantClear(&varg1);
881 ERR("MsiSetProperty returned %d\n", ret);
882 return DISP_E_EXCEPTION;
885 else return DISP_E_MEMBERNOTFOUND;
886 break;
888 case DISPID_SESSION_LANGUAGE:
889 if (wFlags & DISPATCH_PROPERTYGET) {
890 langId = MsiGetLanguage(This->msiHandle);
891 V_VT(pVarResult) = VT_I4;
892 V_I4(pVarResult) = langId;
894 else return DISP_E_MEMBERNOTFOUND;
895 break;
897 case DISPID_SESSION_MODE:
898 if (wFlags & DISPATCH_PROPERTYGET) {
899 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
900 if (FAILED(hr)) return hr;
901 V_VT(pVarResult) = VT_BOOL;
902 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
903 } else if (wFlags & DISPATCH_PROPERTYPUT) {
904 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
905 if (FAILED(hr)) return hr;
906 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
907 if (FAILED(hr)) return hr;
908 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
910 ERR("MsiSetMode returned %d\n", ret);
911 return DISP_E_EXCEPTION;
914 else return DISP_E_MEMBERNOTFOUND;
915 break;
917 case DISPID_SESSION_DATABASE:
918 if (wFlags & DISPATCH_PROPERTYGET) {
919 V_VT(pVarResult) = VT_DISPATCH;
920 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
922 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
924 IDispatch_AddRef(pDispatch);
925 V_DISPATCH(pVarResult) = pDispatch;
927 else
928 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
930 else
932 ERR("MsiGetActiveDatabase failed\n");
933 return DISP_E_EXCEPTION;
936 else return DISP_E_MEMBERNOTFOUND;
937 break;
939 case DISPID_SESSION_DOACTION:
940 if (wFlags & DISPATCH_METHOD) {
941 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
942 if (FAILED(hr)) return hr;
943 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
944 V_VT(pVarResult) = VT_I4;
945 switch (ret)
947 case ERROR_FUNCTION_NOT_CALLED:
948 V_I4(pVarResult) = msiDoActionStatusNoAction;
949 break;
950 case ERROR_SUCCESS:
951 V_I4(pVarResult) = msiDoActionStatusSuccess;
952 break;
953 case ERROR_INSTALL_USEREXIT:
954 V_I4(pVarResult) = msiDoActionStatusUserExit;
955 break;
956 case ERROR_INSTALL_FAILURE:
957 V_I4(pVarResult) = msiDoActionStatusFailure;
958 break;
959 case ERROR_INSTALL_SUSPEND:
960 V_I4(pVarResult) = msiDoActionStatusSuspend;
961 break;
962 case ERROR_MORE_DATA:
963 V_I4(pVarResult) = msiDoActionStatusFinished;
964 break;
965 case ERROR_INVALID_HANDLE_STATE:
966 V_I4(pVarResult) = msiDoActionStatusWrongState;
967 break;
968 case ERROR_INVALID_DATA:
969 V_I4(pVarResult) = msiDoActionStatusBadActionData;
970 break;
971 default:
972 VariantClear(&varg0);
973 FIXME("MsiDoAction returned unhandled value %d\n", ret);
974 return DISP_E_EXCEPTION;
977 else return DISP_E_MEMBERNOTFOUND;
978 break;
980 case DISPID_SESSION_EVALUATECONDITION:
981 if (wFlags & DISPATCH_METHOD) {
982 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
983 if (FAILED(hr)) return hr;
984 V_VT(pVarResult) = VT_I4;
985 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
987 else return DISP_E_MEMBERNOTFOUND;
988 break;
990 case DISPID_SESSION_SETINSTALLLEVEL:
991 if (wFlags & DISPATCH_METHOD) {
992 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
993 if (FAILED(hr)) return hr;
994 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
996 ERR("MsiSetInstallLevel returned %d\n", ret);
997 return DISP_E_EXCEPTION;
1000 else return DISP_E_MEMBERNOTFOUND;
1001 break;
1003 case DISPID_SESSION_FEATURECURRENTSTATE:
1004 if (wFlags & DISPATCH_PROPERTYGET) {
1005 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1006 if (FAILED(hr)) return hr;
1007 V_VT(pVarResult) = VT_I4;
1008 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1009 V_I4(pVarResult) = iInstalled;
1010 else
1012 ERR("MsiGetFeatureState returned %d\n", ret);
1013 V_I4(pVarResult) = msiInstallStateUnknown;
1016 else return DISP_E_MEMBERNOTFOUND;
1017 break;
1019 case DISPID_SESSION_FEATUREREQUESTSTATE:
1020 if (wFlags & DISPATCH_PROPERTYGET) {
1021 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1022 if (FAILED(hr)) return hr;
1023 V_VT(pVarResult) = VT_I4;
1024 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1025 V_I4(pVarResult) = iAction;
1026 else
1028 ERR("MsiGetFeatureState returned %d\n", ret);
1029 V_I4(pVarResult) = msiInstallStateUnknown;
1031 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1032 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1033 if (FAILED(hr)) return hr;
1034 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1035 if (FAILED(hr)) {
1036 VariantClear(&varg0);
1037 return hr;
1039 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1041 VariantClear(&varg0);
1042 ERR("MsiSetFeatureState returned %d\n", ret);
1043 return DISP_E_EXCEPTION;
1046 else return DISP_E_MEMBERNOTFOUND;
1047 break;
1049 default:
1050 return DISP_E_MEMBERNOTFOUND;
1053 VariantClear(&varg1);
1054 VariantClear(&varg0);
1056 return S_OK;
1059 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1060 * registry value type. Used by Installer::RegistryValue. */
1061 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1063 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1064 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1065 WCHAR *szString = (WCHAR *)lpData;
1066 LPWSTR szNewString = NULL;
1067 DWORD dwNewSize = 0;
1068 int idx;
1070 switch (dwType)
1072 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1073 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1074 idx = (dwSize/sizeof(WCHAR))-1;
1075 while (idx >= 0 && !szString[idx]) idx--;
1076 for (; idx >= 0; idx--)
1077 if (!szString[idx]) szString[idx] = '\n';
1078 case REG_SZ:
1079 V_VT(pVarResult) = VT_BSTR;
1080 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1081 break;
1083 case REG_EXPAND_SZ:
1084 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1085 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1086 else if (!(szNewString = msi_alloc(dwNewSize)))
1087 ERR("Out of memory\n");
1088 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1089 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1090 else
1092 V_VT(pVarResult) = VT_BSTR;
1093 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1095 msi_free(szNewString);
1096 break;
1098 case REG_DWORD:
1099 V_VT(pVarResult) = VT_I4;
1100 V_I4(pVarResult) = *((DWORD *)lpData);
1101 break;
1103 case REG_QWORD:
1104 V_VT(pVarResult) = VT_BSTR;
1105 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1106 break;
1108 case REG_BINARY:
1109 V_VT(pVarResult) = VT_BSTR;
1110 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1111 break;
1113 case REG_NONE:
1114 V_VT(pVarResult) = VT_EMPTY;
1115 break;
1117 default:
1118 FIXME("Unhandled registry value type %d\n", dwType);
1122 static HRESULT WINAPI InstallerImpl_Invoke(
1123 AutomationObject* This,
1124 DISPID dispIdMember,
1125 REFIID riid,
1126 LCID lcid,
1127 WORD wFlags,
1128 DISPPARAMS* pDispParams,
1129 VARIANT* pVarResult,
1130 EXCEPINFO* pExcepInfo,
1131 UINT* puArgErr)
1133 MSIHANDLE msiHandle;
1134 IDispatch *pDispatch = NULL;
1135 UINT ret;
1136 VARIANTARG varg0, varg1, varg2;
1137 HRESULT hr;
1139 VariantInit(&varg0);
1140 VariantInit(&varg1);
1141 VariantInit(&varg2);
1143 switch (dispIdMember)
1145 case DISPID_INSTALLER_CREATERECORD:
1146 if (wFlags & DISPATCH_METHOD)
1148 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1149 if (FAILED(hr)) return hr;
1150 V_VT(pVarResult) = VT_DISPATCH;
1151 if ((msiHandle = MsiCreateRecord(V_I4(&varg0))))
1153 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1155 IDispatch_AddRef(pDispatch);
1156 V_DISPATCH(pVarResult) = pDispatch;
1158 else
1159 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1161 else
1163 ERR("MsiCreateRecord failed\n");
1164 return DISP_E_EXCEPTION;
1167 else return DISP_E_MEMBERNOTFOUND;
1168 break;
1170 case DISPID_INSTALLER_OPENPACKAGE:
1171 if (wFlags & DISPATCH_METHOD)
1173 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1174 if (FAILED(hr)) return hr;
1175 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1176 if (FAILED(hr))
1178 VariantClear(&varg0);
1179 return hr;
1181 V_VT(pVarResult) = VT_DISPATCH;
1182 if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
1184 if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
1186 IDispatch_AddRef(pDispatch);
1187 V_DISPATCH(pVarResult) = pDispatch;
1189 else
1190 ERR("Failed to create Session object, hresult 0x%08x\n", hr);
1192 else
1194 VariantClear(&varg0);
1195 ERR("MsiOpenPackageEx returned %d\n", ret);
1196 return DISP_E_EXCEPTION;
1199 else return DISP_E_MEMBERNOTFOUND;
1200 break;
1202 case DISPID_INSTALLER_REGISTRYVALUE:
1203 if (wFlags & DISPATCH_METHOD) {
1204 HKEY hkey;
1205 LPWSTR szString = NULL;
1206 DWORD dwSize = 0, dwType;
1207 UINT posValue = 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1209 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1210 if (FAILED(hr)) return hr;
1211 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1212 if (FAILED(hr)) return hr;
1213 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1214 if (FAILED(hr))
1216 VariantClear(&varg1);
1217 return hr;
1219 ret = RegOpenKeyW((HKEY)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1221 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1222 switch (V_VT(&varg2))
1224 case VT_EMPTY: /* Return VT_BOOL as to whether or not registry key exists */
1225 V_VT(pVarResult) = VT_BOOL;
1226 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1227 break;
1229 case VT_BSTR: /* Return value of specified key if it exists */
1230 if (ret == ERROR_SUCCESS &&
1231 (ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, NULL, NULL, &dwSize)) == ERROR_SUCCESS)
1233 if (!(szString = msi_alloc(dwSize)))
1234 ERR("Out of memory\n");
1235 else if ((ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, &dwType, (LPBYTE)szString, &dwSize)) == ERROR_SUCCESS)
1236 variant_from_registry_value(pVarResult, dwType, (LPBYTE)szString, dwSize);
1239 if (ret != ERROR_SUCCESS)
1241 msi_free(szString);
1242 VariantClear(&varg2);
1243 VariantClear(&varg1);
1244 return DISP_E_BADINDEX;
1246 break;
1248 default: /* Try to make it into VT_I4, can use VariantChangeType for this */
1249 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1250 if (SUCCEEDED(hr) && ret != ERROR_SUCCESS) hr = DISP_E_BADINDEX; /* Conversion fine, but couldn't find key */
1251 if (FAILED(hr))
1253 if (hr == DISP_E_TYPEMISMATCH) *puArgErr = posValue;
1254 VariantClear(&varg2); /* Unknown type, so let's clear it */
1255 VariantClear(&varg1);
1256 return hr;
1259 /* Retrieve class name or maximum value name or subkey name size */
1260 if (!V_I4(&varg2))
1261 ret = RegQueryInfoKeyW(hkey, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1262 else if (V_I4(&varg2) > 0)
1263 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL);
1264 else /* V_I4(&varg2) < 0 */
1265 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
1267 if (ret == ERROR_SUCCESS)
1269 if (!(szString = msi_alloc(++dwSize * sizeof(WCHAR))))
1270 ERR("Out of memory\n");
1271 else if (!V_I4(&varg2))
1272 ret = RegQueryInfoKeyW(hkey, szString, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1273 else if (V_I4(&varg2) > 0)
1274 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString, &dwSize, 0, 0, NULL, NULL);
1275 else /* V_I4(&varg2) < 0 */
1276 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, dwSize);
1278 if (szString && ret == ERROR_SUCCESS)
1280 V_VT(pVarResult) = VT_BSTR;
1281 V_BSTR(pVarResult) = SysAllocString(szString);
1286 msi_free(szString);
1287 RegCloseKey(hkey);
1289 else return DISP_E_MEMBERNOTFOUND;
1290 break;
1292 case DISPID_INSTALLER_PRODUCTSTATE:
1293 if (wFlags & DISPATCH_PROPERTYGET) {
1294 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1295 if (FAILED(hr)) return hr;
1296 V_VT(pVarResult) = VT_I4;
1297 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
1299 else return DISP_E_MEMBERNOTFOUND;
1300 break;
1302 case DISPID_INSTALLER_PRODUCTS:
1303 if (wFlags & DISPATCH_PROPERTYGET)
1305 StringListData *sldata = NULL;
1306 int idx = 0;
1307 WCHAR szProductBuf[GUID_SIZE];
1309 /* Find number of products */
1310 do {
1311 ret = MsiEnumProductsW(idx, szProductBuf);
1312 if (ret == ERROR_SUCCESS) idx++;
1313 } while (ret == ERROR_SUCCESS && ret != ERROR_NO_MORE_ITEMS);
1315 if (ret != ERROR_SUCCESS && ret != ERROR_NO_MORE_ITEMS)
1317 ERR("MsiEnumProducts returned %d\n", ret);
1318 return DISP_E_EXCEPTION;
1321 V_VT(pVarResult) = VT_DISPATCH;
1322 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, StringListImpl_Invoke, StringListImpl_Free, sizeof(StringListData))))
1324 IDispatch_AddRef(pDispatch);
1325 V_DISPATCH(pVarResult) = pDispatch;
1327 /* Save product strings */
1328 sldata = (StringListData *)private_data((AutomationObject *)pDispatch);
1329 sldata->iCount = idx;
1330 sldata->pszStrings = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LPWSTR)*sldata->iCount);
1331 for (idx = 0; idx < sldata->iCount; idx++)
1333 ret = MsiEnumProductsW(idx, szProductBuf);
1334 sldata->pszStrings[idx] = SysAllocString(szProductBuf);
1337 else
1338 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1340 else return DISP_E_MEMBERNOTFOUND;
1341 break;
1343 default:
1344 return DISP_E_MEMBERNOTFOUND;
1347 VariantClear(&varg2);
1348 VariantClear(&varg1);
1349 VariantClear(&varg0);
1351 return S_OK;
1354 /* Wrapper around create_automation_object to create an installer object. */
1355 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
1357 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
1360 /* Wrapper around create_automation_object to create a session object. */
1361 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
1363 HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
1364 if (SUCCEEDED(hr) && pDispatch && *pDispatch)
1365 ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
1366 return hr;