msi: automation: Move VariantClears out of specific case statements when possible.
[wine/wine-gecko.git] / dlls / msi / automation.c
blobc732163001b6bd0be0645fece54eadb00af852ab
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 "msidefs.h"
29 #include "msipriv.h"
30 #include "activscp.h"
31 #include "oleauto.h"
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
35 #include "msiserver.h"
36 #include "msiserver_dispids.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
42 * called from AutomationObject::Invoke, and pass this function to create_automation_object.
45 typedef interface AutomationObject AutomationObject;
47 interface AutomationObject {
49 * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
51 const IDispatchVtbl *lpVtbl;
52 const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
54 /* Object reference count */
55 LONG ref;
57 /* Clsid for this class and it's appropriate ITypeInfo object */
58 LPCLSID clsid;
59 ITypeInfo *iTypeInfo;
61 /* The MSI handle of the current object */
62 MSIHANDLE msiHandle;
64 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
65 HRESULT (STDMETHODCALLTYPE *funcInvoke)(
66 AutomationObject* This,
67 DISPID dispIdMember,
68 REFIID riid,
69 LCID lcid,
70 WORD wFlags,
71 DISPPARAMS* pDispParams,
72 VARIANT* pVarResult,
73 EXCEPINFO* pExcepInfo,
74 UINT* puArgErr);
76 /* A function that is called from AutomationObject::Release when the object is being freed to free any private
77 * data structures (or NULL) */
78 void (STDMETHODCALLTYPE *funcFree)(AutomationObject* This);
82 * Structures for additional data required by specific automation objects
85 typedef struct {
86 int iCount;
87 LPWSTR *pszStrings;
88 } StringListData;
90 typedef struct {
91 /* The parent Installer object */
92 IDispatch *pInstaller;
93 } SessionData;
95 /* VTables */
96 static const struct IDispatchVtbl AutomationObject_Vtbl;
97 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
99 /* Load type info so we don't have to process GetIDsOfNames */
100 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
102 HRESULT hr;
103 LPTYPELIB pLib = NULL;
104 LPTYPEINFO pInfo = NULL;
105 static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
107 TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
109 /* Load registered type library */
110 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
111 if (FAILED(hr)) {
112 hr = LoadTypeLib(szMsiServer, &pLib);
113 if (FAILED(hr)) {
114 ERR("Could not load msiserver.tlb\n");
115 return hr;
119 /* Get type information for object */
120 hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
121 ITypeLib_Release(pLib);
122 if (FAILED(hr)) {
123 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
124 return hr;
126 *pptinfo = pInfo;
127 return S_OK;
130 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
131 * with the appropriate clsid and invocation function. */
132 HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
133 HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
134 VARIANT*,EXCEPINFO*,UINT*),
135 void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
136 SIZE_T sizetPrivateData)
138 AutomationObject *object;
139 HRESULT hr;
141 TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
143 if( pUnkOuter )
144 return CLASS_E_NOAGGREGATION;
146 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData);
148 /* Set all the VTable references */
149 object->lpVtbl = &AutomationObject_Vtbl;
150 object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
151 object->ref = 1;
153 /* Store data that was passed */
154 object->msiHandle = msiHandle;
155 object->clsid = (LPCLSID)clsid;
156 object->funcInvoke = funcInvoke;
157 object->funcFree = funcFree;
159 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
160 object->iTypeInfo = NULL;
161 hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
162 if (FAILED(hr)) {
163 HeapFree(GetProcessHeap(), 0, object);
164 return hr;
167 *ppObj = object;
169 return S_OK;
172 /* Macros to get pointer to AutomationObject from the other VTables. */
173 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
175 return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
178 /* Macro to get pointer to private object data */
179 static inline void *private_data( AutomationObject *This )
181 return This + 1;
185 * AutomationObject methods
188 /*** IUnknown methods ***/
189 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
191 AutomationObject *This = (AutomationObject *)iface;
193 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
195 if (ppvObject == NULL)
196 return E_INVALIDARG;
198 *ppvObject = 0;
200 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
201 *ppvObject = This;
202 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
203 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
204 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
205 *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
206 else
208 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
209 return E_NOINTERFACE;
213 * Query Interface always increases the reference count by one when it is
214 * successful
216 IClassFactory_AddRef(iface);
218 return S_OK;
221 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
223 AutomationObject *This = (AutomationObject *)iface;
225 TRACE("(%p/%p)\n", iface, This);
227 return InterlockedIncrement(&This->ref);
230 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
232 AutomationObject *This = (AutomationObject *)iface;
233 ULONG ref = InterlockedDecrement(&This->ref);
235 TRACE("(%p/%p)\n", iface, This);
237 if (!ref)
239 if (This->funcFree) This->funcFree(This);
240 MsiCloseHandle(This->msiHandle);
241 HeapFree(GetProcessHeap(), 0, This);
244 return ref;
247 /*** IDispatch methods ***/
248 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
249 IDispatch* iface,
250 UINT* pctinfo)
252 AutomationObject *This = (AutomationObject *)iface;
254 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
255 *pctinfo = 1;
256 return S_OK;
259 static HRESULT WINAPI AutomationObject_GetTypeInfo(
260 IDispatch* iface,
261 UINT iTInfo,
262 LCID lcid,
263 ITypeInfo** ppTInfo)
265 AutomationObject *This = (AutomationObject *)iface;
266 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
268 ITypeInfo_AddRef(This->iTypeInfo);
269 *ppTInfo = This->iTypeInfo;
270 return S_OK;
273 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
274 IDispatch* iface,
275 REFIID riid,
276 LPOLESTR* rgszNames,
277 UINT cNames,
278 LCID lcid,
279 DISPID* rgDispId)
281 AutomationObject *This = (AutomationObject *)iface;
282 HRESULT hr;
283 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
285 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
286 hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
287 if (hr == DISP_E_UNKNOWNNAME)
289 int idx;
290 for (idx=0; idx<cNames; idx++)
292 if (rgDispId[idx] == DISPID_UNKNOWN)
293 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
296 return hr;
299 /* Maximum number of allowed function parameters+1 */
300 #define MAX_FUNC_PARAMS 20
302 /* Some error checking is done here to simplify individual object function invocation */
303 static HRESULT WINAPI AutomationObject_Invoke(
304 IDispatch* iface,
305 DISPID dispIdMember,
306 REFIID riid,
307 LCID lcid,
308 WORD wFlags,
309 DISPPARAMS* pDispParams,
310 VARIANT* pVarResult,
311 EXCEPINFO* pExcepInfo,
312 UINT* puArgErr)
314 AutomationObject *This = (AutomationObject *)iface;
315 HRESULT hr;
316 unsigned int uArgErr;
317 VARIANT varResultDummy;
318 BSTR bstrName = NULL;
320 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
322 if (!IsEqualIID(riid, &IID_NULL))
324 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
325 return DISP_E_UNKNOWNNAME;
328 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
330 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
331 return DISP_E_PARAMNOTOPTIONAL;
334 /* This simplifies our individual object invocation functions */
335 if (puArgErr == NULL) puArgErr = &uArgErr;
336 if (pVarResult == NULL) pVarResult = &varResultDummy;
338 /* Assume return type is void unless determined otherwise */
339 VariantInit(pVarResult);
341 /* If we are tracing, we want to see the name of the member we are invoking */
342 if (TRACE_ON(msi))
344 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
345 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
348 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
350 if (hr == DISP_E_MEMBERNOTFOUND) {
351 if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
352 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
354 else if (pExcepInfo &&
355 (hr == DISP_E_PARAMNOTFOUND ||
356 hr == DISP_E_EXCEPTION)) {
357 static const WCHAR szComma[] = { ',',0 };
358 static WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
359 WCHAR szExceptionDescription[MAX_PATH];
360 BSTR bstrParamNames[MAX_FUNC_PARAMS];
361 unsigned namesNo, i;
362 BOOL bFirst = TRUE;
364 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
365 MAX_FUNC_PARAMS, &namesNo)))
367 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
369 else
371 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
372 for (i=0; i<namesNo; i++)
374 if (bFirst) bFirst = FALSE;
375 else {
376 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
378 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
379 SysFreeString(bstrParamNames[i]);
382 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
383 pExcepInfo->wCode = 1000;
384 pExcepInfo->bstrSource = szExceptionSource;
385 pExcepInfo->bstrDescription = szExceptionDescription;
386 hr = DISP_E_EXCEPTION;
390 /* Make sure we free the return variant if it is our dummy variant */
391 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
393 /* Free function name if we retrieved it */
394 if (bstrName) SysFreeString(bstrName);
396 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
398 return hr;
401 static const struct IDispatchVtbl AutomationObject_Vtbl =
403 AutomationObject_QueryInterface,
404 AutomationObject_AddRef,
405 AutomationObject_Release,
406 AutomationObject_GetTypeInfoCount,
407 AutomationObject_GetTypeInfo,
408 AutomationObject_GetIDsOfNames,
409 AutomationObject_Invoke
413 * IProvideMultipleClassInfo methods
416 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
417 IProvideMultipleClassInfo* iface,
418 REFIID riid,
419 VOID** ppvoid)
421 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
422 return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
425 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
427 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
428 return AutomationObject_AddRef((IDispatch *)This);
431 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
433 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
434 return AutomationObject_Release((IDispatch *)This);
437 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
439 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
440 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
441 return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
444 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
446 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
447 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
449 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
450 return E_INVALIDARG;
451 else {
452 *pGUID = *This->clsid;
453 return S_OK;
457 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
459 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
461 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
462 *pcti = 1;
463 return S_OK;
466 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
467 ULONG iti,
468 DWORD dwFlags,
469 ITypeInfo** pptiCoClass,
470 DWORD* pdwTIFlags,
471 ULONG* pcdispidReserved,
472 IID* piidPrimary,
473 IID* piidSource)
475 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
477 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
479 if (iti != 0)
480 return E_INVALIDARG;
482 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
483 load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
485 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
487 *pdwTIFlags = 0;
488 *pcdispidReserved = 0;
491 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
492 *piidPrimary = *This->clsid;
495 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
496 *piidSource = *This->clsid;
499 return S_OK;
502 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
504 AutomationObject_IProvideMultipleClassInfo_QueryInterface,
505 AutomationObject_IProvideMultipleClassInfo_AddRef,
506 AutomationObject_IProvideMultipleClassInfo_Release,
507 AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
508 AutomationObject_IProvideMultipleClassInfo_GetGUID,
509 AutomationObject_GetMultiTypeInfoCount,
510 AutomationObject_GetInfoOfIndex
514 * Individual Object Invocation Functions
517 static HRESULT WINAPI RecordImpl_Invoke(
518 AutomationObject* This,
519 DISPID dispIdMember,
520 REFIID riid,
521 LCID lcid,
522 WORD wFlags,
523 DISPPARAMS* pDispParams,
524 VARIANT* pVarResult,
525 EXCEPINFO* pExcepInfo,
526 UINT* puArgErr)
528 WCHAR *szString;
529 DWORD dwLen;
530 UINT ret;
531 VARIANTARG varg0, varg1;
532 HRESULT hr;
534 VariantInit(&varg0);
535 VariantInit(&varg1);
537 switch (dispIdMember)
539 case DISPID_RECORD_STRINGDATA:
540 if (wFlags & DISPATCH_PROPERTYGET) {
541 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
542 if (FAILED(hr)) return hr;
543 V_VT(pVarResult) = VT_BSTR;
544 V_BSTR(pVarResult) = NULL;
545 ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen);
546 if (ret == ERROR_SUCCESS)
548 szString = msi_alloc((++dwLen)*sizeof(WCHAR));
549 if (szString)
551 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
552 V_BSTR(pVarResult) = SysAllocString(szString);
553 msi_free(szString);
556 if (ret != ERROR_SUCCESS)
557 ERR("MsiRecordGetString returned %d\n", ret);
558 } else if (wFlags & DISPATCH_PROPERTYPUT) {
559 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
560 if (FAILED(hr)) return hr;
561 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
562 if (FAILED(hr)) return hr;
563 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
565 VariantClear(&varg1);
566 ERR("MsiRecordSetString returned %d\n", ret);
567 return DISP_E_EXCEPTION;
570 break;
572 default:
573 return DISP_E_MEMBERNOTFOUND;
576 VariantClear(&varg1);
577 VariantClear(&varg0);
579 return S_OK;
582 static HRESULT WINAPI StringListImpl_Invoke(
583 AutomationObject* This,
584 DISPID dispIdMember,
585 REFIID riid,
586 LCID lcid,
587 WORD wFlags,
588 DISPPARAMS* pDispParams,
589 VARIANT* pVarResult,
590 EXCEPINFO* pExcepInfo,
591 UINT* puArgErr)
593 StringListData *data = (StringListData *)private_data(This);
594 HRESULT hr;
595 VARIANTARG varg0;
597 VariantInit(&varg0);
599 switch (dispIdMember)
601 case DISPID_STRINGLIST_ITEM:
602 if (wFlags & DISPATCH_PROPERTYGET) {
603 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
604 if (FAILED(hr)) return hr;
605 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->iCount)
606 return DISP_E_BADINDEX;
607 V_VT(pVarResult) = VT_BSTR;
608 V_BSTR(pVarResult) = SysAllocString(data->pszStrings[V_I4(&varg0)]);
610 break;
612 case DISPID_STRINGLIST_COUNT:
613 if (wFlags & DISPATCH_PROPERTYGET) {
614 V_VT(pVarResult) = VT_I4;
615 V_I4(pVarResult) = data->iCount;
617 break;
619 default:
620 return DISP_E_MEMBERNOTFOUND;
623 VariantClear(&varg0);
625 return S_OK;
628 static void WINAPI StringListImpl_Free(AutomationObject *This)
630 StringListData *data = private_data(This);
631 int idx;
633 for (idx=0; idx<data->iCount; idx++)
634 SysFreeString(data->pszStrings[idx]);
635 HeapFree(GetProcessHeap(), 0, data->pszStrings);
638 static HRESULT WINAPI ViewImpl_Invoke(
639 AutomationObject* This,
640 DISPID dispIdMember,
641 REFIID riid,
642 LCID lcid,
643 WORD wFlags,
644 DISPPARAMS* pDispParams,
645 VARIANT* pVarResult,
646 EXCEPINFO* pExcepInfo,
647 UINT* puArgErr)
649 MSIHANDLE msiHandle;
650 IDispatch *pDispatch = NULL;
651 UINT ret;
652 VARIANTARG varg0, varg1;
653 HRESULT hr;
655 VariantInit(&varg0);
656 VariantInit(&varg1);
658 switch (dispIdMember)
660 case DISPID_VIEW_EXECUTE:
661 if (wFlags & DISPATCH_METHOD)
663 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
664 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
665 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
666 else
667 MsiViewExecute(This->msiHandle, 0);
669 break;
671 case DISPID_VIEW_FETCH:
672 if (wFlags & DISPATCH_METHOD)
674 V_VT(pVarResult) = VT_DISPATCH;
675 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
677 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
679 IDispatch_AddRef(pDispatch);
680 V_DISPATCH(pVarResult) = pDispatch;
682 else
683 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
685 else if (ret == ERROR_NO_MORE_ITEMS)
686 V_DISPATCH(pVarResult) = NULL;
687 else
689 ERR("MsiViewFetch returned %d\n", ret);
690 return DISP_E_EXCEPTION;
693 break;
695 case DISPID_VIEW_CLOSE:
696 if (wFlags & DISPATCH_METHOD)
698 MsiViewClose(This->msiHandle);
700 break;
702 default:
703 return DISP_E_MEMBERNOTFOUND;
706 VariantClear(&varg1);
707 VariantClear(&varg0);
709 return S_OK;
712 static HRESULT WINAPI DatabaseImpl_Invoke(
713 AutomationObject* This,
714 DISPID dispIdMember,
715 REFIID riid,
716 LCID lcid,
717 WORD wFlags,
718 DISPPARAMS* pDispParams,
719 VARIANT* pVarResult,
720 EXCEPINFO* pExcepInfo,
721 UINT* puArgErr)
723 MSIHANDLE msiHandle;
724 IDispatch *pDispatch = NULL;
725 UINT ret;
726 VARIANTARG varg0, varg1;
727 HRESULT hr;
729 VariantInit(&varg0);
730 VariantInit(&varg1);
732 switch (dispIdMember)
734 case DISPID_DATABASE_OPENVIEW:
735 if (wFlags & DISPATCH_METHOD)
737 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
738 if (FAILED(hr)) return hr;
739 V_VT(pVarResult) = VT_DISPATCH;
740 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
742 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
744 IDispatch_AddRef(pDispatch);
745 V_DISPATCH(pVarResult) = pDispatch;
747 else
748 ERR("Failed to create View object, hresult 0x%08x\n", hr);
750 else
752 VariantClear(&varg0);
753 ERR("MsiDatabaseOpenView returned %d\n", ret);
754 return DISP_E_EXCEPTION;
757 break;
759 default:
760 return DISP_E_MEMBERNOTFOUND;
763 VariantClear(&varg1);
764 VariantClear(&varg0);
766 return S_OK;
769 static HRESULT WINAPI SessionImpl_Invoke(
770 AutomationObject* This,
771 DISPID dispIdMember,
772 REFIID riid,
773 LCID lcid,
774 WORD wFlags,
775 DISPPARAMS* pDispParams,
776 VARIANT* pVarResult,
777 EXCEPINFO* pExcepInfo,
778 UINT* puArgErr)
780 SessionData *data = private_data(This);
781 WCHAR *szString;
782 DWORD dwLen;
783 IDispatch *pDispatch = NULL;
784 MSIHANDLE msiHandle;
785 LANGID langId;
786 UINT ret;
787 INSTALLSTATE iInstalled, iAction;
788 VARIANTARG varg0, varg1;
789 HRESULT hr;
791 VariantInit(&varg0);
792 VariantInit(&varg1);
794 switch (dispIdMember)
796 case DISPID_SESSION_INSTALLER:
797 if (wFlags & DISPATCH_PROPERTYGET) {
798 V_VT(pVarResult) = VT_DISPATCH;
799 IDispatch_AddRef(data->pInstaller);
800 V_DISPATCH(pVarResult) = data->pInstaller;
802 break;
804 case DISPID_SESSION_PROPERTY:
805 if (wFlags & DISPATCH_PROPERTYGET) {
806 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
807 if (FAILED(hr)) return hr;
808 V_VT(pVarResult) = VT_BSTR;
809 V_BSTR(pVarResult) = NULL;
810 ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen);
811 if (ret == ERROR_SUCCESS)
813 szString = msi_alloc((++dwLen)*sizeof(WCHAR));
814 if (szString)
816 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
817 V_BSTR(pVarResult) = SysAllocString(szString);
818 msi_free(szString);
821 if (ret != ERROR_SUCCESS)
822 ERR("MsiGetProperty returned %d\n", ret);
823 } else if (wFlags & DISPATCH_PROPERTYPUT) {
824 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
825 if (FAILED(hr)) return hr;
826 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
827 if (FAILED(hr)) {
828 VariantClear(&varg0);
829 return hr;
831 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
833 VariantClear(&varg0);
834 VariantClear(&varg1);
835 ERR("MsiSetProperty returned %d\n", ret);
836 return DISP_E_EXCEPTION;
839 break;
841 case DISPID_SESSION_LANGUAGE:
842 if (wFlags & DISPATCH_PROPERTYGET) {
843 langId = MsiGetLanguage(This->msiHandle);
844 V_VT(pVarResult) = VT_I4;
845 V_I4(pVarResult) = langId;
847 break;
849 case DISPID_SESSION_MODE:
850 if (wFlags & DISPATCH_PROPERTYGET) {
851 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
852 if (FAILED(hr)) return hr;
853 V_VT(pVarResult) = VT_BOOL;
854 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
855 } else if (wFlags & DISPATCH_PROPERTYPUT) {
856 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
857 if (FAILED(hr)) return hr;
858 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
859 if (FAILED(hr)) return hr;
860 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
862 ERR("MsiSetMode returned %d\n", ret);
863 return DISP_E_EXCEPTION;
866 break;
868 case DISPID_SESSION_DATABASE:
869 if (wFlags & DISPATCH_PROPERTYGET) {
870 V_VT(pVarResult) = VT_DISPATCH;
871 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
873 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
875 IDispatch_AddRef(pDispatch);
876 V_DISPATCH(pVarResult) = pDispatch;
878 else
879 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
881 else
883 ERR("MsiGetActiveDatabase failed\n");
884 return DISP_E_EXCEPTION;
887 break;
889 case DISPID_SESSION_DOACTION:
890 if (wFlags & DISPATCH_METHOD) {
891 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
892 if (FAILED(hr)) return hr;
893 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
894 V_VT(pVarResult) = VT_I4;
895 switch (ret)
897 case ERROR_FUNCTION_NOT_CALLED:
898 V_I4(pVarResult) = msiDoActionStatusNoAction;
899 break;
900 case ERROR_SUCCESS:
901 V_I4(pVarResult) = msiDoActionStatusSuccess;
902 break;
903 case ERROR_INSTALL_USEREXIT:
904 V_I4(pVarResult) = msiDoActionStatusUserExit;
905 break;
906 case ERROR_INSTALL_FAILURE:
907 V_I4(pVarResult) = msiDoActionStatusFailure;
908 break;
909 case ERROR_INSTALL_SUSPEND:
910 V_I4(pVarResult) = msiDoActionStatusSuspend;
911 break;
912 case ERROR_MORE_DATA:
913 V_I4(pVarResult) = msiDoActionStatusFinished;
914 break;
915 case ERROR_INVALID_HANDLE_STATE:
916 V_I4(pVarResult) = msiDoActionStatusWrongState;
917 break;
918 case ERROR_INVALID_DATA:
919 V_I4(pVarResult) = msiDoActionStatusBadActionData;
920 break;
921 default:
922 VariantClear(&varg0);
923 FIXME("MsiDoAction returned unhandled value %d\n", ret);
924 return DISP_E_EXCEPTION;
927 break;
929 case DISPID_SESSION_SETINSTALLLEVEL:
930 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
931 if (FAILED(hr)) return hr;
932 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
934 ERR("MsiSetInstallLevel returned %d\n", ret);
935 return DISP_E_EXCEPTION;
937 break;
939 case DISPID_SESSION_FEATURECURRENTSTATE:
940 if (wFlags & DISPATCH_PROPERTYGET) {
941 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
942 if (FAILED(hr)) return hr;
943 V_VT(pVarResult) = VT_I4;
944 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
945 V_I4(pVarResult) = iInstalled;
946 else
948 ERR("MsiGetFeatureState returned %d\n", ret);
949 V_I4(pVarResult) = msiInstallStateUnknown;
952 break;
954 case DISPID_SESSION_FEATUREREQUESTSTATE:
955 if (wFlags & DISPATCH_PROPERTYGET) {
956 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
957 if (FAILED(hr)) return hr;
958 V_VT(pVarResult) = VT_I4;
959 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
960 V_I4(pVarResult) = iAction;
961 else
963 ERR("MsiGetFeatureState returned %d\n", ret);
964 V_I4(pVarResult) = msiInstallStateUnknown;
966 } else if (wFlags & DISPATCH_PROPERTYPUT) {
967 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
968 if (FAILED(hr)) return hr;
969 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
970 if (FAILED(hr)) {
971 VariantClear(&varg0);
972 return hr;
974 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
976 VariantClear(&varg0);
977 ERR("MsiSetFeatureState returned %d\n", ret);
978 return DISP_E_EXCEPTION;
981 break;
983 default:
984 return DISP_E_MEMBERNOTFOUND;
987 VariantClear(&varg1);
988 VariantClear(&varg0);
990 return S_OK;
993 static HRESULT WINAPI InstallerImpl_Invoke(
994 AutomationObject* This,
995 DISPID dispIdMember,
996 REFIID riid,
997 LCID lcid,
998 WORD wFlags,
999 DISPPARAMS* pDispParams,
1000 VARIANT* pVarResult,
1001 EXCEPINFO* pExcepInfo,
1002 UINT* puArgErr)
1004 MSIHANDLE msiHandle;
1005 IDispatch *pDispatch = NULL;
1006 UINT ret;
1007 VARIANTARG varg0, varg1;
1008 HRESULT hr;
1010 VariantInit(&varg0);
1011 VariantInit(&varg1);
1013 switch (dispIdMember)
1015 case DISPID_INSTALLER_OPENPACKAGE:
1016 if (wFlags & DISPATCH_METHOD)
1018 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1019 if (FAILED(hr)) return hr;
1020 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1021 if (FAILED(hr))
1023 VariantClear(&varg0);
1024 return hr;
1026 V_VT(pVarResult) = VT_DISPATCH;
1027 if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
1029 if (SUCCEEDED(create_session(msiHandle, (IDispatch *)This, &pDispatch)))
1031 IDispatch_AddRef(pDispatch);
1032 V_DISPATCH(pVarResult) = pDispatch;
1035 else
1037 VariantClear(&varg0);
1038 ERR("MsiOpenPackageEx returned %d\n", ret);
1039 return DISP_E_EXCEPTION;
1042 break;
1044 case DISPID_INSTALLER_PRODUCTSTATE:
1045 if (wFlags & DISPATCH_PROPERTYGET) {
1046 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1047 if (FAILED(hr)) return hr;
1048 V_VT(pVarResult) = VT_I4;
1049 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
1051 break;
1053 case DISPID_INSTALLER_PRODUCTS:
1054 if (wFlags & DISPATCH_PROPERTYGET)
1056 StringListData *sldata = NULL;
1057 int idx = 0;
1058 WCHAR szProductBuf[GUID_SIZE];
1060 /* Find number of products */
1061 do {
1062 ret = MsiEnumProductsW(idx, szProductBuf);
1063 if (ret == ERROR_SUCCESS) idx++;
1064 } while (ret == ERROR_SUCCESS && ret != ERROR_NO_MORE_ITEMS);
1066 if (ret != ERROR_SUCCESS && ret != ERROR_NO_MORE_ITEMS)
1068 ERR("MsiEnumProducts returned %d\n", ret);
1069 return DISP_E_EXCEPTION;
1072 V_VT(pVarResult) = VT_DISPATCH;
1073 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, StringListImpl_Invoke, StringListImpl_Free, sizeof(StringListData))))
1075 IDispatch_AddRef(pDispatch);
1076 V_DISPATCH(pVarResult) = pDispatch;
1078 /* Save product strings */
1079 sldata = (StringListData *)private_data((AutomationObject *)pDispatch);
1080 sldata->iCount = idx;
1081 sldata->pszStrings = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LPWSTR)*sldata->iCount);
1082 for (idx = 0; idx < sldata->iCount; idx++)
1084 ret = MsiEnumProductsW(idx, szProductBuf);
1085 sldata->pszStrings[idx] = SysAllocString(szProductBuf);
1088 else
1089 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1091 break;
1093 default:
1094 return DISP_E_MEMBERNOTFOUND;
1097 VariantClear(&varg1);
1098 VariantClear(&varg0);
1100 return S_OK;
1103 /* Wrapper around create_automation_object to create an installer object. */
1104 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
1106 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
1109 /* Wrapper around create_automation_object to create a session object. */
1110 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
1112 HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
1113 if (SUCCEEDED(hr) && pDispatch && *pDispatch)
1114 ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
1115 return hr;