Sync with trunk (r48545)
[reactos.git] / dll / win32 / msi / automation.c
1 /*
2 * Implementation of OLE Automation for Microsoft Installer (msi.dll)
3 *
4 * Copyright 2007 Misha Koshelev
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #define COBJMACROS
22
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"
36
37 #include "msiserver.h"
38 #include "msiserver_dispids.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41
42 #define REG_INDEX_CLASSES_ROOT 0
43 #define REG_INDEX_DYN_DATA 6
44
45 /*
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.
48 */
49
50 typedef interface AutomationObject AutomationObject;
51
52 interface AutomationObject {
53 /*
54 * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
55 */
56 const IDispatchVtbl *lpVtbl;
57 const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
58
59 /* Object reference count */
60 LONG ref;
61
62 /* Clsid for this class and it's appropriate ITypeInfo object */
63 LPCLSID clsid;
64 ITypeInfo *iTypeInfo;
65
66 /* The MSI handle of the current object */
67 MSIHANDLE msiHandle;
68
69 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
70 HRESULT (STDMETHODCALLTYPE *funcInvoke)(
71 AutomationObject* This,
72 DISPID dispIdMember,
73 REFIID riid,
74 LCID lcid,
75 WORD wFlags,
76 DISPPARAMS* pDispParams,
77 VARIANT* pVarResult,
78 EXCEPINFO* pExcepInfo,
79 UINT* puArgErr);
80
81 /* A function that is called from AutomationObject::Release when the object is being freed to free any private
82 * data structures (or NULL) */
83 void (STDMETHODCALLTYPE *funcFree)(AutomationObject* This);
84 };
85
86 /*
87 * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
88 */
89
90 typedef interface ListEnumerator ListEnumerator;
91
92 interface ListEnumerator {
93 /* VTables */
94 const IEnumVARIANTVtbl *lpVtbl;
95
96 /* Object reference count */
97 LONG ref;
98
99 /* Current position and pointer to AutomationObject that stores actual data */
100 ULONG ulPos;
101 AutomationObject *pObj;
102 };
103
104 /*
105 * Structures for additional data required by specific automation objects
106 */
107
108 typedef struct {
109 ULONG ulCount;
110 VARIANT *pVars;
111 } ListData;
112
113 typedef struct {
114 /* The parent Installer object */
115 IDispatch *pInstaller;
116 } SessionData;
117
118 /* VTables */
119 static const struct IDispatchVtbl AutomationObject_Vtbl;
120 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
121 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl;
122
123 /* Load type info so we don't have to process GetIDsOfNames */
124 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
125 {
126 HRESULT hr;
127 LPTYPELIB pLib = NULL;
128 LPTYPEINFO pInfo = NULL;
129 static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
130
131 TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
132
133 /* Load registered type library */
134 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
135 if (FAILED(hr)) {
136 hr = LoadTypeLib(szMsiServer, &pLib);
137 if (FAILED(hr)) {
138 ERR("Could not load msiserver.tlb\n");
139 return hr;
140 }
141 }
142
143 /* Get type information for object */
144 hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
145 ITypeLib_Release(pLib);
146 if (FAILED(hr)) {
147 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
148 return hr;
149 }
150 *pptinfo = pInfo;
151 return S_OK;
152 }
153
154 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
155 * with the appropriate clsid and invocation function. */
156 static HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
157 HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
158 VARIANT*,EXCEPINFO*,UINT*),
159 void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
160 SIZE_T sizetPrivateData)
161 {
162 AutomationObject *object;
163 HRESULT hr;
164
165 TRACE("(%d,%p,%p,%s,%p,%p,%ld)\n", msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
166
167 if( pUnkOuter )
168 return CLASS_E_NOAGGREGATION;
169
170 object = msi_alloc_zero( sizeof(AutomationObject) + sizetPrivateData );
171
172 /* Set all the VTable references */
173 object->lpVtbl = &AutomationObject_Vtbl;
174 object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
175 object->ref = 1;
176
177 /* Store data that was passed */
178 object->msiHandle = msiHandle;
179 object->clsid = (LPCLSID)clsid;
180 object->funcInvoke = funcInvoke;
181 object->funcFree = funcFree;
182
183 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
184 object->iTypeInfo = NULL;
185 hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
186 if (FAILED(hr)) {
187 msi_free( object );
188 return hr;
189 }
190
191 *ppObj = object;
192
193 return S_OK;
194 }
195
196 /* Create a list enumerator, placing the result in the pointer ppObj. */
197 static HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos)
198 {
199 ListEnumerator *object;
200
201 TRACE("(%p,%p,%p,%uld)\n", pUnkOuter, ppObj, pObj, ulPos);
202
203 if( pUnkOuter )
204 return CLASS_E_NOAGGREGATION;
205
206 object = msi_alloc_zero( sizeof(ListEnumerator) );
207
208 /* Set all the VTable references */
209 object->lpVtbl = &ListEnumerator_Vtbl;
210 object->ref = 1;
211
212 /* Store data that was passed */
213 object->ulPos = ulPos;
214 object->pObj = pObj;
215 if (pObj) IDispatch_AddRef((IDispatch *)pObj);
216
217 *ppObj = object;
218 return S_OK;
219 }
220
221 /* Macros to get pointer to AutomationObject from the other VTables. */
222 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
223 {
224 return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
225 }
226
227 /* Macro to get pointer to private object data */
228 static inline void *private_data( AutomationObject *This )
229 {
230 return This + 1;
231 }
232
233 /*
234 * AutomationObject methods
235 */
236
237 /*** IUnknown methods ***/
238 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
239 {
240 AutomationObject *This = (AutomationObject *)iface;
241
242 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
243
244 if (ppvObject == NULL)
245 return E_INVALIDARG;
246
247 *ppvObject = 0;
248
249 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
250 *ppvObject = This;
251 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
252 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
253 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
254 *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
255 else
256 {
257 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
258 return E_NOINTERFACE;
259 }
260
261 /*
262 * Query Interface always increases the reference count by one when it is
263 * successful
264 */
265 IClassFactory_AddRef(iface);
266
267 return S_OK;
268 }
269
270 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
271 {
272 AutomationObject *This = (AutomationObject *)iface;
273
274 TRACE("(%p/%p)\n", iface, This);
275
276 return InterlockedIncrement(&This->ref);
277 }
278
279 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
280 {
281 AutomationObject *This = (AutomationObject *)iface;
282 ULONG ref = InterlockedDecrement(&This->ref);
283
284 TRACE("(%p/%p)\n", iface, This);
285
286 if (!ref)
287 {
288 if (This->funcFree) This->funcFree(This);
289 ITypeInfo_Release(This->iTypeInfo);
290 MsiCloseHandle(This->msiHandle);
291 msi_free(This);
292 }
293
294 return ref;
295 }
296
297 /*** IDispatch methods ***/
298 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
299 IDispatch* iface,
300 UINT* pctinfo)
301 {
302 AutomationObject *This = (AutomationObject *)iface;
303
304 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
305 *pctinfo = 1;
306 return S_OK;
307 }
308
309 static HRESULT WINAPI AutomationObject_GetTypeInfo(
310 IDispatch* iface,
311 UINT iTInfo,
312 LCID lcid,
313 ITypeInfo** ppTInfo)
314 {
315 AutomationObject *This = (AutomationObject *)iface;
316 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
317
318 ITypeInfo_AddRef(This->iTypeInfo);
319 *ppTInfo = This->iTypeInfo;
320 return S_OK;
321 }
322
323 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
324 IDispatch* iface,
325 REFIID riid,
326 LPOLESTR* rgszNames,
327 UINT cNames,
328 LCID lcid,
329 DISPID* rgDispId)
330 {
331 AutomationObject *This = (AutomationObject *)iface;
332 HRESULT hr;
333 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
334
335 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
336 hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
337 if (hr == DISP_E_UNKNOWNNAME)
338 {
339 UINT idx;
340 for (idx=0; idx<cNames; idx++)
341 {
342 if (rgDispId[idx] == DISPID_UNKNOWN)
343 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
344 }
345 }
346 return hr;
347 }
348
349 /* Maximum number of allowed function parameters+1 */
350 #define MAX_FUNC_PARAMS 20
351
352 /* Some error checking is done here to simplify individual object function invocation */
353 static HRESULT WINAPI AutomationObject_Invoke(
354 IDispatch* iface,
355 DISPID dispIdMember,
356 REFIID riid,
357 LCID lcid,
358 WORD wFlags,
359 DISPPARAMS* pDispParams,
360 VARIANT* pVarResult,
361 EXCEPINFO* pExcepInfo,
362 UINT* puArgErr)
363 {
364 AutomationObject *This = (AutomationObject *)iface;
365 HRESULT hr;
366 unsigned int uArgErr;
367 VARIANT varResultDummy;
368 BSTR bstrName = NULL;
369
370 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
371
372 if (!IsEqualIID(riid, &IID_NULL))
373 {
374 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
375 return DISP_E_UNKNOWNNAME;
376 }
377
378 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
379 {
380 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
381 return DISP_E_PARAMNOTOPTIONAL;
382 }
383
384 /* This simplifies our individual object invocation functions */
385 if (puArgErr == NULL) puArgErr = &uArgErr;
386 if (pVarResult == NULL) pVarResult = &varResultDummy;
387
388 /* Assume return type is void unless determined otherwise */
389 VariantInit(pVarResult);
390
391 /* If we are tracing, we want to see the name of the member we are invoking */
392 if (TRACE_ON(msi))
393 {
394 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
395 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
396 }
397
398 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
399
400 if (hr == DISP_E_MEMBERNOTFOUND) {
401 if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
402 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
403 }
404 else if (pExcepInfo &&
405 (hr == DISP_E_PARAMNOTFOUND ||
406 hr == DISP_E_EXCEPTION)) {
407 static const WCHAR szComma[] = { ',',0 };
408 static const WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
409 WCHAR szExceptionDescription[MAX_PATH];
410 BSTR bstrParamNames[MAX_FUNC_PARAMS];
411 unsigned namesNo, i;
412 BOOL bFirst = TRUE;
413
414 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
415 MAX_FUNC_PARAMS, &namesNo)))
416 {
417 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
418 }
419 else
420 {
421 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
422 for (i=0; i<namesNo; i++)
423 {
424 if (bFirst) bFirst = FALSE;
425 else {
426 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
427 }
428 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
429 SysFreeString(bstrParamNames[i]);
430 }
431
432 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
433 pExcepInfo->wCode = 1000;
434 pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
435 pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
436 hr = DISP_E_EXCEPTION;
437 }
438 }
439
440 /* Make sure we free the return variant if it is our dummy variant */
441 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
442
443 /* Free function name if we retrieved it */
444 SysFreeString(bstrName);
445
446 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
447
448 return hr;
449 }
450
451 static const struct IDispatchVtbl AutomationObject_Vtbl =
452 {
453 AutomationObject_QueryInterface,
454 AutomationObject_AddRef,
455 AutomationObject_Release,
456 AutomationObject_GetTypeInfoCount,
457 AutomationObject_GetTypeInfo,
458 AutomationObject_GetIDsOfNames,
459 AutomationObject_Invoke
460 };
461
462 /*
463 * IProvideMultipleClassInfo methods
464 */
465
466 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
467 IProvideMultipleClassInfo* iface,
468 REFIID riid,
469 VOID** ppvoid)
470 {
471 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
472 return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
473 }
474
475 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
476 {
477 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
478 return AutomationObject_AddRef((IDispatch *)This);
479 }
480
481 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
482 {
483 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
484 return AutomationObject_Release((IDispatch *)This);
485 }
486
487 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
488 {
489 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
490 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
491 return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
492 }
493
494 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
495 {
496 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
497 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
498
499 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
500 return E_INVALIDARG;
501 else {
502 *pGUID = *This->clsid;
503 return S_OK;
504 }
505 }
506
507 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
508 {
509 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
510
511 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
512 *pcti = 1;
513 return S_OK;
514 }
515
516 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
517 ULONG iti,
518 DWORD dwFlags,
519 ITypeInfo** pptiCoClass,
520 DWORD* pdwTIFlags,
521 ULONG* pcdispidReserved,
522 IID* piidPrimary,
523 IID* piidSource)
524 {
525 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
526
527 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
528
529 if (iti != 0)
530 return E_INVALIDARG;
531
532 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
533 load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
534
535 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
536 {
537 *pdwTIFlags = 0;
538 *pcdispidReserved = 0;
539 }
540
541 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
542 *piidPrimary = *This->clsid;
543 }
544
545 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
546 *piidSource = *This->clsid;
547 }
548
549 return S_OK;
550 }
551
552 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
553 {
554 AutomationObject_IProvideMultipleClassInfo_QueryInterface,
555 AutomationObject_IProvideMultipleClassInfo_AddRef,
556 AutomationObject_IProvideMultipleClassInfo_Release,
557 AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
558 AutomationObject_IProvideMultipleClassInfo_GetGUID,
559 AutomationObject_GetMultiTypeInfoCount,
560 AutomationObject_GetInfoOfIndex
561 };
562
563 /*
564 * ListEnumerator methods
565 */
566
567 /*** IUnknown methods ***/
568 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, void** ppvObject)
569 {
570 ListEnumerator *This = (ListEnumerator *)iface;
571
572 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
573
574 if (ppvObject == NULL)
575 return E_INVALIDARG;
576
577 *ppvObject = 0;
578
579 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT))
580 *ppvObject = This;
581 else
582 {
583 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
584 return E_NOINTERFACE;
585 }
586
587 IClassFactory_AddRef(iface);
588 return S_OK;
589 }
590
591 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
592 {
593 ListEnumerator *This = (ListEnumerator *)iface;
594
595 TRACE("(%p/%p)\n", iface, This);
596
597 return InterlockedIncrement(&This->ref);
598 }
599
600 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
601 {
602 ListEnumerator *This = (ListEnumerator *)iface;
603 ULONG ref = InterlockedDecrement(&This->ref);
604
605 TRACE("(%p/%p)\n", iface, This);
606
607 if (!ref)
608 {
609 if (This->pObj) IDispatch_Release((IDispatch *)This->pObj);
610 msi_free(This);
611 }
612
613 return ref;
614 }
615
616 /* IEnumVARIANT methods */
617
618 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
619 {
620 ListEnumerator *This = (ListEnumerator *)iface;
621 ListData *data = private_data(This->pObj);
622 ULONG idx, local;
623
624 TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched);
625
626 if (pCeltFetched != NULL)
627 *pCeltFetched = 0;
628
629 if (rgVar == NULL)
630 return S_FALSE;
631
632 for (local = 0; local < celt; local++)
633 VariantInit(&rgVar[local]);
634
635 for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++)
636 VariantCopy(&rgVar[local], &data->pVars[idx]);
637
638 if (pCeltFetched != NULL)
639 *pCeltFetched = local;
640 This->ulPos = idx;
641
642 return (local < celt) ? S_FALSE : S_OK;
643 }
644
645 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
646 {
647 ListEnumerator *This = (ListEnumerator *)iface;
648 ListData *data = private_data(This->pObj);
649
650 TRACE("(%p,%uld)\n", iface, celt);
651
652 This->ulPos += celt;
653 if (This->ulPos >= data->ulCount)
654 {
655 This->ulPos = data->ulCount;
656 return S_FALSE;
657 }
658 return S_OK;
659 }
660
661 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
662 {
663 ListEnumerator *This = (ListEnumerator *)iface;
664
665 TRACE("(%p)\n", iface);
666
667 This->ulPos = 0;
668 return S_OK;
669 }
670
671 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
672 {
673 ListEnumerator *This = (ListEnumerator *)iface;
674 HRESULT hr;
675
676 TRACE("(%p,%p)\n", iface, ppEnum);
677
678 if (ppEnum == NULL)
679 return S_FALSE;
680
681 *ppEnum = NULL;
682 hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0);
683 if (FAILED(hr))
684 {
685 if (*ppEnum)
686 IUnknown_Release(*ppEnum);
687 return hr;
688 }
689
690 return S_OK;
691 }
692
693 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
694 {
695 ListEnumerator_QueryInterface,
696 ListEnumerator_AddRef,
697 ListEnumerator_Release,
698 ListEnumerator_Next,
699 ListEnumerator_Skip,
700 ListEnumerator_Reset,
701 ListEnumerator_Clone
702 };
703
704 /*
705 * Individual Object Invocation Functions
706 */
707
708 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
709 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
710 using DispGetParam/VariantChangeType. */
711 static HRESULT DispGetParam_CopyOnly(
712 DISPPARAMS *pdispparams, /* [in] Parameter list */
713 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
714 VARIANT *pvarResult) /* [out] Destination for resulting variant */
715 {
716 /* position is counted backwards */
717 UINT pos;
718
719 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
720 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
721 if (*position < pdispparams->cArgs) {
722 /* positional arg? */
723 pos = pdispparams->cArgs - *position - 1;
724 } else {
725 /* FIXME: is this how to handle named args? */
726 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
727 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
728
729 if (pos==pdispparams->cNamedArgs)
730 return DISP_E_PARAMNOTFOUND;
731 }
732 *position = pos;
733 return VariantCopyInd(pvarResult,
734 &pdispparams->rgvarg[pos]);
735 }
736
737 static HRESULT WINAPI SummaryInfoImpl_Invoke(
738 AutomationObject* This,
739 DISPID dispIdMember,
740 REFIID riid,
741 LCID lcid,
742 WORD wFlags,
743 DISPPARAMS* pDispParams,
744 VARIANT* pVarResult,
745 EXCEPINFO* pExcepInfo,
746 UINT* puArgErr)
747 {
748 UINT ret;
749 VARIANTARG varg0, varg1;
750 FILETIME ft, ftlocal;
751 SYSTEMTIME st;
752 HRESULT hr;
753
754 VariantInit(&varg0);
755 VariantInit(&varg1);
756
757 switch (dispIdMember)
758 {
759 case DISPID_SUMMARYINFO_PROPERTY:
760 if (wFlags & DISPATCH_PROPERTYGET)
761 {
762 UINT type;
763 INT value;
764 DWORD size = 0;
765 DATE date;
766 LPWSTR str;
767
768 static WCHAR szEmpty[] = {0};
769
770 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
771 if (FAILED(hr)) return hr;
772 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
773 &ft, szEmpty, &size);
774 if (ret != ERROR_SUCCESS &&
775 ret != ERROR_MORE_DATA)
776 {
777 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
778 return DISP_E_EXCEPTION;
779 }
780
781 switch (type)
782 {
783 case VT_EMPTY:
784 break;
785
786 case VT_I2:
787 case VT_I4:
788 V_VT(pVarResult) = VT_I4;
789 V_I4(pVarResult) = value;
790 break;
791
792 case VT_LPSTR:
793 if (!(str = msi_alloc(++size * sizeof(WCHAR))))
794 ERR("Out of memory\n");
795 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
796 NULL, str, &size)) != ERROR_SUCCESS)
797 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
798 else
799 {
800 V_VT(pVarResult) = VT_BSTR;
801 V_BSTR(pVarResult) = SysAllocString(str);
802 }
803 msi_free(str);
804 break;
805
806 case VT_FILETIME:
807 FileTimeToLocalFileTime(&ft, &ftlocal);
808 FileTimeToSystemTime(&ftlocal, &st);
809 SystemTimeToVariantTime(&st, &date);
810
811 V_VT(pVarResult) = VT_DATE;
812 V_DATE(pVarResult) = date;
813 break;
814
815 default:
816 ERR("Unhandled variant type %d\n", type);
817 }
818 }
819 else if (wFlags & DISPATCH_PROPERTYPUT)
820 {
821 UINT posValue = DISPID_PROPERTYPUT;
822
823 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
824 if (FAILED(hr)) return hr;
825 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
826 if (FAILED(hr))
827 {
828 *puArgErr = posValue;
829 return hr;
830 }
831
832 switch (V_VT(&varg1))
833 {
834 case VT_I2:
835 case VT_I4:
836 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
837 break;
838
839 case VT_DATE:
840 VariantTimeToSystemTime(V_DATE(&varg1), &st);
841 SystemTimeToFileTime(&st, &ftlocal);
842 LocalFileTimeToFileTime(&ftlocal, &ft);
843 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
844 break;
845
846 case VT_BSTR:
847 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
848 break;
849
850 default:
851 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
852 VariantClear(&varg1);
853 return DISP_E_EXCEPTION;
854 }
855
856 if (ret != ERROR_SUCCESS)
857 {
858 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
859 return DISP_E_EXCEPTION;
860 }
861 }
862 else return DISP_E_MEMBERNOTFOUND;
863 break;
864
865 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
866 if (wFlags & DISPATCH_PROPERTYGET) {
867 UINT count;
868 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
869 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
870 else
871 {
872 V_VT(pVarResult) = VT_I4;
873 V_I4(pVarResult) = count;
874 }
875 }
876 else return DISP_E_MEMBERNOTFOUND;
877 break;
878
879 default:
880 return DISP_E_MEMBERNOTFOUND;
881 }
882
883 VariantClear(&varg1);
884 VariantClear(&varg0);
885
886 return S_OK;
887 }
888
889 static HRESULT WINAPI RecordImpl_Invoke(
890 AutomationObject* This,
891 DISPID dispIdMember,
892 REFIID riid,
893 LCID lcid,
894 WORD wFlags,
895 DISPPARAMS* pDispParams,
896 VARIANT* pVarResult,
897 EXCEPINFO* pExcepInfo,
898 UINT* puArgErr)
899 {
900 WCHAR *szString;
901 DWORD dwLen;
902 UINT ret;
903 VARIANTARG varg0, varg1;
904 HRESULT hr;
905
906 VariantInit(&varg0);
907 VariantInit(&varg1);
908
909 switch (dispIdMember)
910 {
911 case DISPID_RECORD_FIELDCOUNT:
912 if (wFlags & DISPATCH_PROPERTYGET) {
913 V_VT(pVarResult) = VT_I4;
914 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
915 }
916 else return DISP_E_MEMBERNOTFOUND;
917 break;
918
919 case DISPID_RECORD_STRINGDATA:
920 if (wFlags & DISPATCH_PROPERTYGET) {
921 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
922 if (FAILED(hr)) return hr;
923 V_VT(pVarResult) = VT_BSTR;
924 V_BSTR(pVarResult) = NULL;
925 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
926 {
927 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
928 ERR("Out of memory\n");
929 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
930 V_BSTR(pVarResult) = SysAllocString(szString);
931 msi_free(szString);
932 }
933 if (ret != ERROR_SUCCESS)
934 ERR("MsiRecordGetString returned %d\n", ret);
935 } else if (wFlags & DISPATCH_PROPERTYPUT) {
936 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
937 if (FAILED(hr)) return hr;
938 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
939 if (FAILED(hr)) return hr;
940 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
941 {
942 VariantClear(&varg1);
943 ERR("MsiRecordSetString returned %d\n", ret);
944 return DISP_E_EXCEPTION;
945 }
946 }
947 else return DISP_E_MEMBERNOTFOUND;
948 break;
949
950 case DISPID_RECORD_INTEGERDATA:
951 if (wFlags & DISPATCH_PROPERTYGET) {
952 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
953 if (FAILED(hr)) return hr;
954 V_VT(pVarResult) = VT_I4;
955 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
956 } else if (wFlags & DISPATCH_PROPERTYPUT) {
957 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
958 if (FAILED(hr)) return hr;
959 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
960 if (FAILED(hr)) return hr;
961 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
962 {
963 ERR("MsiRecordSetInteger returned %d\n", ret);
964 return DISP_E_EXCEPTION;
965 }
966 }
967 else return DISP_E_MEMBERNOTFOUND;
968 break;
969
970 default:
971 return DISP_E_MEMBERNOTFOUND;
972 }
973
974 VariantClear(&varg1);
975 VariantClear(&varg0);
976
977 return S_OK;
978 }
979
980 static HRESULT WINAPI ListImpl_Invoke(
981 AutomationObject* This,
982 DISPID dispIdMember,
983 REFIID riid,
984 LCID lcid,
985 WORD wFlags,
986 DISPPARAMS* pDispParams,
987 VARIANT* pVarResult,
988 EXCEPINFO* pExcepInfo,
989 UINT* puArgErr)
990 {
991 ListData *data = private_data(This);
992 HRESULT hr;
993 VARIANTARG varg0;
994 IUnknown *pUnk = NULL;
995
996 VariantInit(&varg0);
997
998 switch (dispIdMember)
999 {
1000 case DISPID_LIST__NEWENUM:
1001 if (wFlags & DISPATCH_METHOD) {
1002 V_VT(pVarResult) = VT_UNKNOWN;
1003 if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0)))
1004 V_UNKNOWN(pVarResult) = pUnk;
1005 else
1006 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
1007 }
1008 else return DISP_E_MEMBERNOTFOUND;
1009 break;
1010
1011 case DISPID_LIST_ITEM:
1012 if (wFlags & DISPATCH_PROPERTYGET) {
1013 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1014 if (FAILED(hr)) return hr;
1015 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount)
1016 return DISP_E_BADINDEX;
1017 VariantCopy(pVarResult, &data->pVars[V_I4(&varg0)]);
1018 }
1019 else return DISP_E_MEMBERNOTFOUND;
1020 break;
1021
1022 case DISPID_LIST_COUNT:
1023 if (wFlags & DISPATCH_PROPERTYGET) {
1024 V_VT(pVarResult) = VT_I4;
1025 V_I4(pVarResult) = data->ulCount;
1026 }
1027 else return DISP_E_MEMBERNOTFOUND;
1028 break;
1029
1030 default:
1031 return DISP_E_MEMBERNOTFOUND;
1032 }
1033
1034 VariantClear(&varg0);
1035
1036 return S_OK;
1037 }
1038
1039 static void WINAPI ListImpl_Free(AutomationObject *This)
1040 {
1041 ListData *data = private_data(This);
1042 ULONG idx;
1043
1044 for (idx=0; idx<data->ulCount; idx++)
1045 VariantClear(&data->pVars[idx]);
1046 msi_free(data->pVars);
1047 }
1048
1049 static HRESULT WINAPI ViewImpl_Invoke(
1050 AutomationObject* This,
1051 DISPID dispIdMember,
1052 REFIID riid,
1053 LCID lcid,
1054 WORD wFlags,
1055 DISPPARAMS* pDispParams,
1056 VARIANT* pVarResult,
1057 EXCEPINFO* pExcepInfo,
1058 UINT* puArgErr)
1059 {
1060 MSIHANDLE msiHandle;
1061 IDispatch *pDispatch = NULL;
1062 UINT ret;
1063 VARIANTARG varg0, varg1;
1064 HRESULT hr;
1065
1066 VariantInit(&varg0);
1067 VariantInit(&varg1);
1068
1069 switch (dispIdMember)
1070 {
1071 case DISPID_VIEW_EXECUTE:
1072 if (wFlags & DISPATCH_METHOD)
1073 {
1074 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1075 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1076 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1077 else
1078 MsiViewExecute(This->msiHandle, 0);
1079 }
1080 else return DISP_E_MEMBERNOTFOUND;
1081 break;
1082
1083 case DISPID_VIEW_FETCH:
1084 if (wFlags & DISPATCH_METHOD)
1085 {
1086 V_VT(pVarResult) = VT_DISPATCH;
1087 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1088 {
1089 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1090 V_DISPATCH(pVarResult) = pDispatch;
1091 else
1092 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1093 }
1094 else if (ret == ERROR_NO_MORE_ITEMS)
1095 V_DISPATCH(pVarResult) = NULL;
1096 else
1097 {
1098 ERR("MsiViewFetch returned %d\n", ret);
1099 return DISP_E_EXCEPTION;
1100 }
1101 }
1102 else return DISP_E_MEMBERNOTFOUND;
1103 break;
1104
1105 case DISPID_VIEW_MODIFY:
1106 if (wFlags & DISPATCH_METHOD)
1107 {
1108 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1109 if (FAILED(hr)) return hr;
1110 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1111 if (FAILED(hr)) return hr;
1112 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1113 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1114 {
1115 VariantClear(&varg1);
1116 ERR("MsiViewModify returned %d\n", ret);
1117 return DISP_E_EXCEPTION;
1118 }
1119 }
1120 else return DISP_E_MEMBERNOTFOUND;
1121 break;
1122
1123 case DISPID_VIEW_CLOSE:
1124 if (wFlags & DISPATCH_METHOD)
1125 {
1126 MsiViewClose(This->msiHandle);
1127 }
1128 else return DISP_E_MEMBERNOTFOUND;
1129 break;
1130
1131 default:
1132 return DISP_E_MEMBERNOTFOUND;
1133 }
1134
1135 VariantClear(&varg1);
1136 VariantClear(&varg0);
1137
1138 return S_OK;
1139 }
1140
1141 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
1142 DISPPARAMS* pDispParams,
1143 VARIANT* pVarResult,
1144 EXCEPINFO* pExcepInfo,
1145 UINT* puArgErr)
1146 {
1147 if (!(wFlags & DISPATCH_METHOD))
1148 return DISP_E_MEMBERNOTFOUND;
1149
1150 FIXME("\n");
1151
1152 VariantInit(pVarResult);
1153 return S_OK;
1154 }
1155
1156 static HRESULT WINAPI DatabaseImpl_Invoke(
1157 AutomationObject* This,
1158 DISPID dispIdMember,
1159 REFIID riid,
1160 LCID lcid,
1161 WORD wFlags,
1162 DISPPARAMS* pDispParams,
1163 VARIANT* pVarResult,
1164 EXCEPINFO* pExcepInfo,
1165 UINT* puArgErr)
1166 {
1167 MSIHANDLE msiHandle;
1168 IDispatch *pDispatch = NULL;
1169 UINT ret;
1170 VARIANTARG varg0, varg1;
1171 HRESULT hr;
1172
1173 VariantInit(&varg0);
1174 VariantInit(&varg1);
1175
1176 switch (dispIdMember)
1177 {
1178 case DISPID_DATABASE_SUMMARYINFORMATION:
1179 if (wFlags & DISPATCH_PROPERTYGET)
1180 {
1181 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1182 if (FAILED(hr))
1183 V_I4(&varg0) = 0;
1184
1185 V_VT(pVarResult) = VT_DISPATCH;
1186 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1187 {
1188 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0);
1189 if (SUCCEEDED(hr))
1190 V_DISPATCH(pVarResult) = pDispatch;
1191 else
1192 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1193 }
1194 else
1195 {
1196 ERR("MsiGetSummaryInformation returned %d\n", ret);
1197 return DISP_E_EXCEPTION;
1198 }
1199 }
1200 else return DISP_E_MEMBERNOTFOUND;
1201 break;
1202
1203 case DISPID_DATABASE_OPENVIEW:
1204 if (wFlags & DISPATCH_METHOD)
1205 {
1206 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1207 if (FAILED(hr)) return hr;
1208 V_VT(pVarResult) = VT_DISPATCH;
1209 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1210 {
1211 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1212 V_DISPATCH(pVarResult) = pDispatch;
1213 else
1214 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1215 }
1216 else
1217 {
1218 VariantClear(&varg0);
1219 ERR("MsiDatabaseOpenView returned %d\n", ret);
1220 return DISP_E_EXCEPTION;
1221 }
1222 }
1223 else return DISP_E_MEMBERNOTFOUND;
1224 break;
1225
1226 case DISPID_INSTALLER_LASTERRORRECORD:
1227 return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
1228 pVarResult, pExcepInfo,
1229 puArgErr);
1230
1231 default:
1232 return DISP_E_MEMBERNOTFOUND;
1233 }
1234
1235 VariantClear(&varg1);
1236 VariantClear(&varg0);
1237
1238 return S_OK;
1239 }
1240
1241 static HRESULT WINAPI SessionImpl_Invoke(
1242 AutomationObject* This,
1243 DISPID dispIdMember,
1244 REFIID riid,
1245 LCID lcid,
1246 WORD wFlags,
1247 DISPPARAMS* pDispParams,
1248 VARIANT* pVarResult,
1249 EXCEPINFO* pExcepInfo,
1250 UINT* puArgErr)
1251 {
1252 SessionData *data = private_data(This);
1253 WCHAR *szString;
1254 DWORD dwLen;
1255 IDispatch *pDispatch = NULL;
1256 MSIHANDLE msiHandle;
1257 LANGID langId;
1258 UINT ret;
1259 INSTALLSTATE iInstalled, iAction;
1260 VARIANTARG varg0, varg1;
1261 HRESULT hr;
1262
1263 VariantInit(&varg0);
1264 VariantInit(&varg1);
1265
1266 switch (dispIdMember)
1267 {
1268 case DISPID_SESSION_INSTALLER:
1269 if (wFlags & DISPATCH_PROPERTYGET) {
1270 V_VT(pVarResult) = VT_DISPATCH;
1271 IDispatch_AddRef(data->pInstaller);
1272 V_DISPATCH(pVarResult) = data->pInstaller;
1273 }
1274 else return DISP_E_MEMBERNOTFOUND;
1275 break;
1276
1277 case DISPID_SESSION_PROPERTY:
1278 if (wFlags & DISPATCH_PROPERTYGET) {
1279 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1280 if (FAILED(hr)) return hr;
1281 V_VT(pVarResult) = VT_BSTR;
1282 V_BSTR(pVarResult) = NULL;
1283 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1284 {
1285 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1286 ERR("Out of memory\n");
1287 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1288 V_BSTR(pVarResult) = SysAllocString(szString);
1289 msi_free(szString);
1290 }
1291 if (ret != ERROR_SUCCESS)
1292 ERR("MsiGetProperty returned %d\n", ret);
1293 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1294 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1295 if (FAILED(hr)) return hr;
1296 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1297 if (FAILED(hr)) {
1298 VariantClear(&varg0);
1299 return hr;
1300 }
1301 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1302 {
1303 VariantClear(&varg0);
1304 VariantClear(&varg1);
1305 ERR("MsiSetProperty returned %d\n", ret);
1306 return DISP_E_EXCEPTION;
1307 }
1308 }
1309 else return DISP_E_MEMBERNOTFOUND;
1310 break;
1311
1312 case DISPID_SESSION_LANGUAGE:
1313 if (wFlags & DISPATCH_PROPERTYGET) {
1314 langId = MsiGetLanguage(This->msiHandle);
1315 V_VT(pVarResult) = VT_I4;
1316 V_I4(pVarResult) = langId;
1317 }
1318 else return DISP_E_MEMBERNOTFOUND;
1319 break;
1320
1321 case DISPID_SESSION_MODE:
1322 if (wFlags & DISPATCH_PROPERTYGET) {
1323 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1324 if (FAILED(hr)) return hr;
1325 V_VT(pVarResult) = VT_BOOL;
1326 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1327 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1328 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1329 if (FAILED(hr)) return hr;
1330 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1331 if (FAILED(hr)) return hr;
1332 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1333 {
1334 ERR("MsiSetMode returned %d\n", ret);
1335 return DISP_E_EXCEPTION;
1336 }
1337 }
1338 else return DISP_E_MEMBERNOTFOUND;
1339 break;
1340
1341 case DISPID_SESSION_DATABASE:
1342 if (wFlags & DISPATCH_PROPERTYGET) {
1343 V_VT(pVarResult) = VT_DISPATCH;
1344 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1345 {
1346 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1347 V_DISPATCH(pVarResult) = pDispatch;
1348 else
1349 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1350 }
1351 else
1352 {
1353 ERR("MsiGetActiveDatabase failed\n");
1354 return DISP_E_EXCEPTION;
1355 }
1356 }
1357 else return DISP_E_MEMBERNOTFOUND;
1358 break;
1359
1360 case DISPID_SESSION_DOACTION:
1361 if (wFlags & DISPATCH_METHOD) {
1362 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1363 if (FAILED(hr)) return hr;
1364 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1365 V_VT(pVarResult) = VT_I4;
1366 switch (ret)
1367 {
1368 case ERROR_FUNCTION_NOT_CALLED:
1369 V_I4(pVarResult) = msiDoActionStatusNoAction;
1370 break;
1371 case ERROR_SUCCESS:
1372 V_I4(pVarResult) = msiDoActionStatusSuccess;
1373 break;
1374 case ERROR_INSTALL_USEREXIT:
1375 V_I4(pVarResult) = msiDoActionStatusUserExit;
1376 break;
1377 case ERROR_INSTALL_FAILURE:
1378 V_I4(pVarResult) = msiDoActionStatusFailure;
1379 break;
1380 case ERROR_INSTALL_SUSPEND:
1381 V_I4(pVarResult) = msiDoActionStatusSuspend;
1382 break;
1383 case ERROR_MORE_DATA:
1384 V_I4(pVarResult) = msiDoActionStatusFinished;
1385 break;
1386 case ERROR_INVALID_HANDLE_STATE:
1387 V_I4(pVarResult) = msiDoActionStatusWrongState;
1388 break;
1389 case ERROR_INVALID_DATA:
1390 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1391 break;
1392 default:
1393 VariantClear(&varg0);
1394 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1395 return DISP_E_EXCEPTION;
1396 }
1397 }
1398 else return DISP_E_MEMBERNOTFOUND;
1399 break;
1400
1401 case DISPID_SESSION_EVALUATECONDITION:
1402 if (wFlags & DISPATCH_METHOD) {
1403 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1404 if (FAILED(hr)) return hr;
1405 V_VT(pVarResult) = VT_I4;
1406 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1407 }
1408 else return DISP_E_MEMBERNOTFOUND;
1409 break;
1410
1411 case DISPID_SESSION_MESSAGE:
1412 if(!(wFlags & DISPATCH_METHOD))
1413 return DISP_E_MEMBERNOTFOUND;
1414
1415 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1416 if (FAILED(hr)) return hr;
1417 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1418 if (FAILED(hr)) return hr;
1419
1420 V_VT(pVarResult) = VT_I4;
1421 V_I4(pVarResult) =
1422 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
1423 break;
1424
1425 case DISPID_SESSION_SETINSTALLLEVEL:
1426 if (wFlags & DISPATCH_METHOD) {
1427 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1428 if (FAILED(hr)) return hr;
1429 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1430 {
1431 ERR("MsiSetInstallLevel returned %d\n", ret);
1432 return DISP_E_EXCEPTION;
1433 }
1434 }
1435 else return DISP_E_MEMBERNOTFOUND;
1436 break;
1437
1438 case DISPID_SESSION_FEATURECURRENTSTATE:
1439 if (wFlags & DISPATCH_PROPERTYGET) {
1440 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1441 if (FAILED(hr)) return hr;
1442 V_VT(pVarResult) = VT_I4;
1443 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1444 V_I4(pVarResult) = iInstalled;
1445 else
1446 {
1447 ERR("MsiGetFeatureState returned %d\n", ret);
1448 V_I4(pVarResult) = msiInstallStateUnknown;
1449 }
1450 }
1451 else return DISP_E_MEMBERNOTFOUND;
1452 break;
1453
1454 case DISPID_SESSION_FEATUREREQUESTSTATE:
1455 if (wFlags & DISPATCH_PROPERTYGET) {
1456 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1457 if (FAILED(hr)) return hr;
1458 V_VT(pVarResult) = VT_I4;
1459 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1460 V_I4(pVarResult) = iAction;
1461 else
1462 {
1463 ERR("MsiGetFeatureState returned %d\n", ret);
1464 V_I4(pVarResult) = msiInstallStateUnknown;
1465 }
1466 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1467 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1468 if (FAILED(hr)) return hr;
1469 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1470 if (FAILED(hr)) {
1471 VariantClear(&varg0);
1472 return hr;
1473 }
1474 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1475 {
1476 VariantClear(&varg0);
1477 ERR("MsiSetFeatureState returned %d\n", ret);
1478 return DISP_E_EXCEPTION;
1479 }
1480 }
1481 else return DISP_E_MEMBERNOTFOUND;
1482 break;
1483
1484 default:
1485 return DISP_E_MEMBERNOTFOUND;
1486 }
1487
1488 VariantClear(&varg1);
1489 VariantClear(&varg0);
1490
1491 return S_OK;
1492 }
1493
1494 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1495 * registry value type. Used by Installer::RegistryValue. */
1496 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1497 {
1498 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1499 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1500 WCHAR *szString = (WCHAR *)lpData;
1501 LPWSTR szNewString = NULL;
1502 DWORD dwNewSize = 0;
1503 int idx;
1504
1505 switch (dwType)
1506 {
1507 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1508 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1509 idx = (dwSize/sizeof(WCHAR))-1;
1510 while (idx >= 0 && !szString[idx]) idx--;
1511 for (; idx >= 0; idx--)
1512 if (!szString[idx]) szString[idx] = '\n';
1513 case REG_SZ:
1514 V_VT(pVarResult) = VT_BSTR;
1515 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1516 break;
1517
1518 case REG_EXPAND_SZ:
1519 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1520 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1521 else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1522 ERR("Out of memory\n");
1523 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1524 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1525 else
1526 {
1527 V_VT(pVarResult) = VT_BSTR;
1528 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1529 }
1530 msi_free(szNewString);
1531 break;
1532
1533 case REG_DWORD:
1534 V_VT(pVarResult) = VT_I4;
1535 V_I4(pVarResult) = *((DWORD *)lpData);
1536 break;
1537
1538 case REG_QWORD:
1539 V_VT(pVarResult) = VT_BSTR;
1540 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1541 break;
1542
1543 case REG_BINARY:
1544 V_VT(pVarResult) = VT_BSTR;
1545 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1546 break;
1547
1548 case REG_NONE:
1549 V_VT(pVarResult) = VT_EMPTY;
1550 break;
1551
1552 default:
1553 FIXME("Unhandled registry value type %d\n", dwType);
1554 }
1555 }
1556
1557 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1558 DISPPARAMS* pDispParams,
1559 VARIANT* pVarResult,
1560 EXCEPINFO* pExcepInfo,
1561 UINT* puArgErr)
1562 {
1563 HRESULT hr;
1564 VARIANTARG varg0;
1565 MSIHANDLE hrec;
1566 IDispatch* dispatch;
1567
1568 if (!(wFlags & DISPATCH_METHOD))
1569 return DISP_E_MEMBERNOTFOUND;
1570
1571 VariantInit(&varg0);
1572 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1573 if (FAILED(hr))
1574 return hr;
1575
1576 V_VT(pVarResult) = VT_DISPATCH;
1577
1578 hrec = MsiCreateRecord(V_I4(&varg0));
1579 if (!hrec)
1580 return DISP_E_EXCEPTION;
1581
1582 hr = create_automation_object(hrec, NULL, (LPVOID*)&dispatch,
1583 &DIID_Record, RecordImpl_Invoke, NULL, 0);
1584 if (SUCCEEDED(hr))
1585 V_DISPATCH(pVarResult) = dispatch;
1586
1587 return hr;
1588 }
1589
1590 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1591 WORD wFlags,
1592 DISPPARAMS* pDispParams,
1593 VARIANT* pVarResult,
1594 EXCEPINFO* pExcepInfo,
1595 UINT* puArgErr)
1596 {
1597 UINT ret;
1598 HRESULT hr;
1599 MSIHANDLE hpkg;
1600 IDispatch* dispatch;
1601 VARIANTARG varg0, varg1;
1602
1603 if (!(wFlags & DISPATCH_METHOD))
1604 return DISP_E_MEMBERNOTFOUND;
1605
1606 if (pDispParams->cArgs == 0)
1607 return DISP_E_TYPEMISMATCH;
1608
1609 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1610 return DISP_E_TYPEMISMATCH;
1611
1612 VariantInit(&varg0);
1613 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1614 if (FAILED(hr))
1615 return hr;
1616
1617 VariantInit(&varg1);
1618 if (pDispParams->cArgs == 2)
1619 {
1620 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1621 if (FAILED(hr))
1622 goto done;
1623 }
1624 else
1625 {
1626 V_VT(&varg1) = VT_I4;
1627 V_I4(&varg1) = 0;
1628 }
1629
1630 V_VT(pVarResult) = VT_DISPATCH;
1631
1632 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1633 if (ret != ERROR_SUCCESS)
1634 {
1635 hr = DISP_E_EXCEPTION;
1636 goto done;
1637 }
1638
1639 hr = create_session(hpkg, (IDispatch *)This, &dispatch);
1640 if (SUCCEEDED(hr))
1641 V_DISPATCH(pVarResult) = dispatch;
1642
1643 done:
1644 VariantClear(&varg0);
1645 VariantClear(&varg1);
1646 return hr;
1647 }
1648
1649 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1650 DISPPARAMS* pDispParams,
1651 VARIANT* pVarResult,
1652 EXCEPINFO* pExcepInfo,
1653 UINT* puArgErr)
1654 {
1655 HRESULT hr;
1656 VARIANTARG varg0;
1657
1658 if (!(wFlags & DISPATCH_METHOD))
1659 return DISP_E_MEMBERNOTFOUND;
1660
1661 VariantInit(&varg0);
1662 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1663 if (FAILED(hr))
1664 return hr;
1665
1666 FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1667
1668 VariantInit(pVarResult);
1669
1670 VariantClear(&varg0);
1671 return S_OK;
1672 }
1673
1674 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1675 DISPPARAMS* pDispParams,
1676 VARIANT* pVarResult,
1677 EXCEPINFO* pExcepInfo,
1678 UINT* puArgErr)
1679 {
1680 UINT ret;
1681 HRESULT hr;
1682 MSIHANDLE hdb;
1683 IDispatch* dispatch;
1684 VARIANTARG varg0, varg1;
1685
1686 if (!(wFlags & DISPATCH_METHOD))
1687 return DISP_E_MEMBERNOTFOUND;
1688
1689 VariantInit(&varg0);
1690 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1691 if (FAILED(hr))
1692 return hr;
1693
1694 VariantInit(&varg1);
1695 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1696 if (FAILED(hr))
1697 goto done;
1698
1699 V_VT(pVarResult) = VT_DISPATCH;
1700
1701 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1702 if (ret != ERROR_SUCCESS)
1703 {
1704 hr = DISP_E_EXCEPTION;
1705 goto done;
1706 }
1707
1708 hr = create_automation_object(hdb, NULL, (LPVOID *)&dispatch,
1709 &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1710 if (SUCCEEDED(hr))
1711 V_DISPATCH(pVarResult) = dispatch;
1712
1713 done:
1714 VariantClear(&varg0);
1715 VariantClear(&varg1);
1716 return hr;
1717 }
1718
1719 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1720 DISPPARAMS* pDispParams,
1721 VARIANT* pVarResult,
1722 EXCEPINFO* pExcepInfo,
1723 UINT* puArgErr)
1724 {
1725 if (!(wFlags & DISPATCH_METHOD))
1726 return DISP_E_MEMBERNOTFOUND;
1727
1728 FIXME("\n");
1729
1730 VariantInit(pVarResult);
1731 return S_OK;
1732 }
1733
1734 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1735 DISPPARAMS* pDispParams,
1736 VARIANT* pVarResult,
1737 EXCEPINFO* pExcepInfo,
1738 UINT* puArgErr)
1739 {
1740 HRESULT hr;
1741 VARIANTARG varg0;
1742 INSTALLUILEVEL ui;
1743
1744 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1745 return DISP_E_MEMBERNOTFOUND;
1746
1747 if (wFlags & DISPATCH_PROPERTYPUT)
1748 {
1749 VariantInit(&varg0);
1750 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1751 if (FAILED(hr))
1752 return hr;
1753
1754 ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1755 if (ui == INSTALLUILEVEL_NOCHANGE)
1756 return DISP_E_EXCEPTION;
1757 }
1758 else if (wFlags & DISPATCH_PROPERTYGET)
1759 {
1760 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1761 if (ui == INSTALLUILEVEL_NOCHANGE)
1762 return DISP_E_EXCEPTION;
1763
1764 V_VT(pVarResult) = VT_I4;
1765 V_I4(pVarResult) = ui;
1766 }
1767
1768 return S_OK;
1769 }
1770
1771 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1772 DISPPARAMS* pDispParams,
1773 VARIANT* pVarResult,
1774 EXCEPINFO* pExcepInfo,
1775 UINT* puArgErr)
1776 {
1777 if (!(wFlags & DISPATCH_METHOD))
1778 return DISP_E_MEMBERNOTFOUND;
1779
1780 FIXME("\n");
1781
1782 VariantInit(pVarResult);
1783 return S_OK;
1784 }
1785
1786 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1787 DISPPARAMS* pDispParams,
1788 VARIANT* pVarResult,
1789 EXCEPINFO* pExcepInfo,
1790 UINT* puArgErr)
1791 {
1792 UINT ret;
1793 HRESULT hr;
1794 VARIANTARG varg0, varg1;
1795
1796 if (!(wFlags & DISPATCH_METHOD))
1797 return DISP_E_MEMBERNOTFOUND;
1798
1799 VariantInit(&varg0);
1800 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1801 if (FAILED(hr))
1802 return hr;
1803
1804 VariantInit(&varg1);
1805 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1806 if (FAILED(hr))
1807 goto done;
1808
1809 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1810 if (ret != ERROR_SUCCESS)
1811 {
1812 hr = DISP_E_EXCEPTION;
1813 goto done;
1814 }
1815
1816 done:
1817 VariantClear(&varg0);
1818 VariantClear(&varg1);
1819 return hr;
1820 }
1821
1822 static HRESULT InstallerImpl_Version(WORD wFlags,
1823 VARIANT* pVarResult,
1824 EXCEPINFO* pExcepInfo,
1825 UINT* puArgErr)
1826 {
1827 HRESULT hr;
1828 DLLVERSIONINFO verinfo;
1829 WCHAR version[MAX_PATH];
1830
1831 static const WCHAR format[] = {
1832 '%','d','.','%','d','.','%','d','.','%','d',0};
1833
1834 if (!(wFlags & DISPATCH_PROPERTYGET))
1835 return DISP_E_MEMBERNOTFOUND;
1836
1837 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1838 hr = DllGetVersion(&verinfo);
1839 if (FAILED(hr))
1840 return hr;
1841
1842 sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1843 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1844
1845 V_VT(pVarResult) = VT_BSTR;
1846 V_BSTR(pVarResult) = SysAllocString(version);
1847 return S_OK;
1848 }
1849
1850 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1851 DISPPARAMS* pDispParams,
1852 VARIANT* pVarResult,
1853 EXCEPINFO* pExcepInfo,
1854 UINT* puArgErr)
1855 {
1856 if (!(wFlags & DISPATCH_METHOD))
1857 return DISP_E_MEMBERNOTFOUND;
1858
1859 FIXME("\n");
1860
1861 VariantInit(pVarResult);
1862 return S_OK;
1863 }
1864
1865 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1866 DISPPARAMS* pDispParams,
1867 VARIANT* pVarResult,
1868 EXCEPINFO* pExcepInfo,
1869 UINT* puArgErr)
1870 {
1871 UINT ret;
1872 HKEY hkey = NULL;
1873 HRESULT hr;
1874 UINT posValue;
1875 DWORD type, size;
1876 LPWSTR szString = NULL;
1877 VARIANTARG varg0, varg1, varg2;
1878
1879 if (!(wFlags & DISPATCH_METHOD))
1880 return DISP_E_MEMBERNOTFOUND;
1881
1882 VariantInit(&varg0);
1883 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1884 if (FAILED(hr))
1885 return hr;
1886
1887 VariantInit(&varg1);
1888 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1889 if (FAILED(hr))
1890 goto done;
1891
1892 /* Save valuePos so we can save puArgErr if we are unable to do our type
1893 * conversions.
1894 */
1895 posValue = 2;
1896 VariantInit(&varg2);
1897 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1898 if (FAILED(hr))
1899 goto done;
1900
1901 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
1902 V_I4(&varg0) <= REG_INDEX_DYN_DATA)
1903 {
1904 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
1905 }
1906
1907 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1908
1909 /* Only VT_EMPTY case can do anything if the key doesn't exist. */
1910 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
1911 {
1912 hr = DISP_E_BADINDEX;
1913 goto done;
1914 }
1915
1916 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1917 switch (V_VT(&varg2))
1918 {
1919 /* Return VT_BOOL clarifying whether registry key exists or not. */
1920 case VT_EMPTY:
1921 V_VT(pVarResult) = VT_BOOL;
1922 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1923 break;
1924
1925 /* Return the value of specified key if it exists. */
1926 case VT_BSTR:
1927 ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
1928 NULL, NULL, NULL, &size);
1929 if (ret != ERROR_SUCCESS)
1930 {
1931 hr = DISP_E_BADINDEX;
1932 goto done;
1933 }
1934
1935 szString = msi_alloc(size);
1936 if (!szString)
1937 {
1938 hr = E_OUTOFMEMORY;
1939 goto done;
1940 }
1941
1942 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
1943 &type, (LPBYTE)szString, &size);
1944 if (ret != ERROR_SUCCESS)
1945 {
1946 msi_free(szString);
1947 hr = DISP_E_BADINDEX;
1948 goto done;
1949 }
1950
1951 variant_from_registry_value(pVarResult, type,
1952 (LPBYTE)szString, size);
1953 msi_free(szString);
1954 break;
1955
1956 /* Try to make it into VT_I4, can use VariantChangeType for this. */
1957 default:
1958 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1959 if (FAILED(hr))
1960 {
1961 if (hr == DISP_E_TYPEMISMATCH)
1962 *puArgErr = posValue;
1963
1964 goto done;
1965 }
1966
1967 /* Retrieve class name or maximum value name or subkey name size. */
1968 if (!V_I4(&varg2))
1969 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
1970 NULL, NULL, NULL, NULL, NULL, NULL);
1971 else if (V_I4(&varg2) > 0)
1972 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
1973 NULL, NULL, &size, NULL, NULL, NULL);
1974 else /* V_I4(&varg2) < 0 */
1975 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
1976 NULL, NULL, NULL, NULL, NULL, NULL);
1977
1978 if (ret != ERROR_SUCCESS)
1979 goto done;
1980
1981 szString = msi_alloc(++size * sizeof(WCHAR));
1982 if (!szString)
1983 {
1984 hr = E_OUTOFMEMORY;
1985 goto done;
1986 }
1987
1988 if (!V_I4(&varg2))
1989 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
1990 NULL, NULL, NULL, NULL, NULL, NULL);
1991 else if (V_I4(&varg2) > 0)
1992 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
1993 &size, 0, 0, NULL, NULL);
1994 else /* V_I4(&varg2) < 0 */
1995 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
1996
1997 if (ret == ERROR_SUCCESS)
1998 {
1999 V_VT(pVarResult) = VT_BSTR;
2000 V_BSTR(pVarResult) = SysAllocString(szString);
2001 }
2002
2003 msi_free(szString);
2004 }
2005
2006 done:
2007 VariantClear(&varg0);
2008 VariantClear(&varg1);
2009 VariantClear(&varg2);
2010 RegCloseKey(hkey);
2011 return hr;
2012 }
2013
2014 static HRESULT InstallerImpl_Environment(WORD wFlags,
2015 DISPPARAMS* pDispParams,
2016 VARIANT* pVarResult,
2017 EXCEPINFO* pExcepInfo,
2018 UINT* puArgErr)
2019 {
2020 if (!(wFlags & DISPATCH_METHOD))
2021 return DISP_E_MEMBERNOTFOUND;
2022
2023 FIXME("\n");
2024
2025 VariantInit(pVarResult);
2026 return S_OK;
2027 }
2028
2029 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2030 DISPPARAMS* pDispParams,
2031 VARIANT* pVarResult,
2032 EXCEPINFO* pExcepInfo,
2033 UINT* puArgErr)
2034 {
2035 if (!(wFlags & DISPATCH_METHOD))
2036 return DISP_E_MEMBERNOTFOUND;
2037
2038 FIXME("\n");
2039
2040 VariantInit(pVarResult);
2041 return S_OK;
2042 }
2043
2044 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2045 DISPPARAMS* pDispParams,
2046 VARIANT* pVarResult,
2047 EXCEPINFO* pExcepInfo,
2048 UINT* puArgErr)
2049 {
2050 if (!(wFlags & DISPATCH_METHOD))
2051 return DISP_E_MEMBERNOTFOUND;
2052
2053 FIXME("\n");
2054
2055 VariantInit(pVarResult);
2056 return S_OK;
2057 }
2058
2059 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2060 DISPPARAMS* pDispParams,
2061 VARIANT* pVarResult,
2062 EXCEPINFO* pExcepInfo,
2063 UINT* puArgErr)
2064 {
2065 if (!(wFlags & DISPATCH_METHOD))
2066 return DISP_E_MEMBERNOTFOUND;
2067
2068 FIXME("\n");
2069
2070 VariantInit(pVarResult);
2071 return S_OK;
2072 }
2073
2074 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2075 DISPPARAMS* pDispParams,
2076 VARIANT* pVarResult,
2077 EXCEPINFO* pExcepInfo,
2078 UINT* puArgErr)
2079 {
2080 HRESULT hr;
2081 VARIANTARG varg0;
2082
2083 if (!(wFlags & DISPATCH_PROPERTYGET))
2084 return DISP_E_MEMBERNOTFOUND;
2085
2086 VariantInit(&varg0);
2087 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2088 if (FAILED(hr))
2089 return hr;
2090
2091 V_VT(pVarResult) = VT_I4;
2092 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2093
2094 VariantClear(&varg0);
2095 return S_OK;
2096 }
2097
2098 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2099 DISPPARAMS* pDispParams,
2100 VARIANT* pVarResult,
2101 EXCEPINFO* pExcepInfo,
2102 UINT* puArgErr)
2103 {
2104 UINT ret;
2105 HRESULT hr;
2106 DWORD size;
2107 LPWSTR str = NULL;
2108 VARIANTARG varg0, varg1;
2109
2110 if (!(wFlags & DISPATCH_PROPERTYGET))
2111 return DISP_E_MEMBERNOTFOUND;
2112
2113 VariantInit(&varg0);
2114 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2115 if (FAILED(hr))
2116 return hr;
2117
2118 VariantInit(&varg1);
2119 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2120 if (FAILED(hr))
2121 goto done;
2122
2123 V_VT(pVarResult) = VT_BSTR;
2124 V_BSTR(pVarResult) = NULL;
2125
2126 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2127 if (ret != ERROR_SUCCESS)
2128 {
2129 hr = DISP_E_EXCEPTION;
2130 goto done;
2131 }
2132
2133 str = msi_alloc(++size * sizeof(WCHAR));
2134 if (!str)
2135 {
2136 hr = E_OUTOFMEMORY;
2137 goto done;
2138 }
2139
2140 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2141 if (ret != ERROR_SUCCESS)
2142 {
2143 hr = DISP_E_EXCEPTION;
2144 goto done;
2145 }
2146
2147 V_BSTR(pVarResult) = SysAllocString(str);
2148 hr = S_OK;
2149
2150 done:
2151 msi_free(str);
2152 VariantClear(&varg0);
2153 VariantClear(&varg1);
2154 return hr;
2155 }
2156
2157 static void cleanup_products(IDispatch* dispatch, ULONG count)
2158 {
2159 UINT i;
2160 ListData* ldata = private_data((AutomationObject *)dispatch);
2161
2162 for (i = 0; i < count - 1; i++)
2163 VariantClear(&ldata->pVars[i]);
2164
2165 ldata->ulCount = 0;
2166 msi_free(ldata->pVars);
2167
2168 IDispatch_Release(dispatch);
2169 }
2170
2171 static HRESULT InstallerImpl_Products(WORD wFlags,
2172 DISPPARAMS* pDispParams,
2173 VARIANT* pVarResult,
2174 EXCEPINFO* pExcepInfo,
2175 UINT* puArgErr)
2176 {
2177 UINT ret;
2178 HRESULT hr;
2179 ULONG idx = 0;
2180 ListData *ldata;
2181 IDispatch *dispatch;
2182 WCHAR product[GUID_SIZE];
2183
2184 if (!(wFlags & DISPATCH_PROPERTYGET))
2185 return DISP_E_MEMBERNOTFOUND;
2186
2187 /* Find number of products. */
2188 while ((ret = MsiEnumProductsW(idx, product)) == ERROR_SUCCESS)
2189 idx++;
2190
2191 if (ret != ERROR_NO_MORE_ITEMS)
2192 return DISP_E_EXCEPTION;
2193
2194 V_VT(pVarResult) = VT_DISPATCH;
2195 hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2196 &DIID_StringList, ListImpl_Invoke,
2197 ListImpl_Free, sizeof(ListData));
2198 if (FAILED(hr))
2199 return hr;
2200
2201 V_DISPATCH(pVarResult) = dispatch;
2202
2203 /* Save product strings. */
2204 ldata = private_data((AutomationObject *)dispatch);
2205 ldata->ulCount = 0;
2206 ldata->pVars = msi_alloc_zero(sizeof(VARIANT) * idx);
2207 if (!ldata->pVars)
2208 {
2209 IDispatch_Release(dispatch);
2210 return E_OUTOFMEMORY;
2211 }
2212
2213 ldata->ulCount = idx;
2214 for (idx = 0; idx < ldata->ulCount; idx++)
2215 {
2216 ret = MsiEnumProductsW(idx, product);
2217 if (ret != ERROR_SUCCESS)
2218 {
2219 cleanup_products(dispatch, idx - 1);
2220 return DISP_E_EXCEPTION;
2221 }
2222
2223 VariantInit(&ldata->pVars[idx]);
2224 V_VT(&ldata->pVars[idx]) = VT_BSTR;
2225 V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2226 }
2227
2228 return S_OK;
2229 }
2230
2231 static HRESULT InstallerImpl_RelatedProducts(WORD wFlags,
2232 DISPPARAMS* pDispParams,
2233 VARIANT* pVarResult,
2234 EXCEPINFO* pExcepInfo,
2235 UINT* puArgErr)
2236 {
2237 UINT ret;
2238 ULONG idx;
2239 HRESULT hr;
2240 ListData *ldata;
2241 VARIANTARG varg0;
2242 IDispatch* dispatch;
2243 WCHAR product[GUID_SIZE];
2244
2245 if (!(wFlags & DISPATCH_PROPERTYGET))
2246 return DISP_E_MEMBERNOTFOUND;
2247
2248 VariantInit(&varg0);
2249 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2250 if (FAILED(hr))
2251 return hr;
2252
2253 /* Find number of related products. */
2254 idx = 0;
2255 do
2256 {
2257 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2258 if (ret == ERROR_SUCCESS)
2259 idx++;
2260 } while (ret == ERROR_SUCCESS);
2261
2262 if (ret != ERROR_NO_MORE_ITEMS)
2263 {
2264 hr = DISP_E_EXCEPTION;
2265 goto done;
2266 }
2267
2268 V_VT(pVarResult) = VT_DISPATCH;
2269
2270 hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2271 &DIID_StringList, ListImpl_Invoke,
2272 ListImpl_Free, sizeof(ListData));
2273 if (FAILED(hr))
2274 goto done;
2275
2276 V_DISPATCH(pVarResult) = dispatch;
2277
2278 /* Save product strings. */
2279 ldata = private_data((AutomationObject *)dispatch);
2280 ldata->pVars = msi_alloc(sizeof(VARIANT) * idx);
2281 if (!ldata->pVars)
2282 {
2283 IDispatch_Release(dispatch);
2284 hr = E_OUTOFMEMORY;
2285 goto done;
2286 }
2287
2288 ldata->ulCount = idx;
2289 for (idx = 0; idx < ldata->ulCount; idx++)
2290 {
2291 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2292 if (ret != ERROR_SUCCESS)
2293 {
2294 cleanup_products(dispatch, idx - 1);
2295 hr = DISP_E_EXCEPTION;
2296 goto done;
2297 }
2298
2299 VariantInit(&ldata->pVars[idx]);
2300 V_VT(&ldata->pVars[idx]) = VT_BSTR;
2301 V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2302 }
2303
2304 hr = S_OK;
2305
2306 done:
2307 VariantClear(&varg0);
2308 return hr;
2309 }
2310
2311 static HRESULT WINAPI InstallerImpl_Invoke(
2312 AutomationObject* This,
2313 DISPID dispIdMember,
2314 REFIID riid,
2315 LCID lcid,
2316 WORD wFlags,
2317 DISPPARAMS* pDispParams,
2318 VARIANT* pVarResult,
2319 EXCEPINFO* pExcepInfo,
2320 UINT* puArgErr)
2321 {
2322 switch (dispIdMember)
2323 {
2324 case DISPID_INSTALLER_CREATERECORD:
2325 return InstallerImpl_CreateRecord(wFlags, pDispParams,
2326 pVarResult, pExcepInfo, puArgErr);
2327
2328 case DISPID_INSTALLER_OPENPACKAGE:
2329 return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2330 pVarResult, pExcepInfo, puArgErr);
2331
2332 case DISPID_INSTALLER_OPENPRODUCT:
2333 return InstallerImpl_OpenProduct(wFlags, pDispParams,
2334 pVarResult, pExcepInfo, puArgErr);
2335
2336 case DISPID_INSTALLER_OPENDATABASE:
2337 return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2338 pVarResult, pExcepInfo, puArgErr);
2339
2340 case DISPID_INSTALLER_SUMMARYINFORMATION:
2341 return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2342 pVarResult, pExcepInfo,
2343 puArgErr);
2344
2345 case DISPID_INSTALLER_UILEVEL:
2346 return InstallerImpl_UILevel(wFlags, pDispParams,
2347 pVarResult, pExcepInfo, puArgErr);
2348
2349 case DISPID_INSTALLER_ENABLELOG:
2350 return InstallerImpl_EnableLog(wFlags, pDispParams,
2351 pVarResult, pExcepInfo, puArgErr);
2352
2353 case DISPID_INSTALLER_INSTALLPRODUCT:
2354 return InstallerImpl_InstallProduct(wFlags, pDispParams,
2355 pVarResult, pExcepInfo,
2356 puArgErr);
2357
2358 case DISPID_INSTALLER_VERSION:
2359 return InstallerImpl_Version(wFlags, pVarResult,
2360 pExcepInfo, puArgErr);
2361
2362 case DISPID_INSTALLER_LASTERRORRECORD:
2363 return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2364 pVarResult, pExcepInfo,
2365 puArgErr);
2366
2367 case DISPID_INSTALLER_REGISTRYVALUE:
2368 return InstallerImpl_RegistryValue(wFlags, pDispParams,
2369 pVarResult, pExcepInfo,
2370 puArgErr);
2371
2372 case DISPID_INSTALLER_ENVIRONMENT:
2373 return InstallerImpl_Environment(wFlags, pDispParams,
2374 pVarResult, pExcepInfo, puArgErr);
2375
2376 case DISPID_INSTALLER_FILEATTRIBUTES:
2377 return InstallerImpl_FileAttributes(wFlags, pDispParams,
2378 pVarResult, pExcepInfo,
2379 puArgErr);
2380
2381 case DISPID_INSTALLER_FILESIZE:
2382 return InstallerImpl_FileSize(wFlags, pDispParams,
2383 pVarResult, pExcepInfo, puArgErr);
2384
2385 case DISPID_INSTALLER_FILEVERSION:
2386 return InstallerImpl_FileVersion(wFlags, pDispParams,
2387 pVarResult, pExcepInfo, puArgErr);
2388
2389 case DISPID_INSTALLER_PRODUCTSTATE:
2390 return InstallerImpl_ProductState(wFlags, pDispParams,
2391 pVarResult, pExcepInfo, puArgErr);
2392
2393 case DISPID_INSTALLER_PRODUCTINFO:
2394 return InstallerImpl_ProductInfo(wFlags, pDispParams,
2395 pVarResult, pExcepInfo, puArgErr);
2396
2397 case DISPID_INSTALLER_PRODUCTS:
2398 return InstallerImpl_Products(wFlags, pDispParams,
2399 pVarResult, pExcepInfo, puArgErr);
2400
2401 case DISPID_INSTALLER_RELATEDPRODUCTS:
2402 return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2403 pVarResult, pExcepInfo,
2404 puArgErr);
2405
2406 default:
2407 return DISP_E_MEMBERNOTFOUND;
2408 }
2409 }
2410
2411 /* Wrapper around create_automation_object to create an installer object. */
2412 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
2413 {
2414 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
2415 }
2416
2417 /* Wrapper around create_automation_object to create a session object. */
2418 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
2419 {
2420 HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
2421 if (SUCCEEDED(hr) && pDispatch && *pDispatch)
2422 ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
2423 return hr;
2424 }