d62c989e530dfb804cc3bf56cf0d4adeb4b53e03
[reactos.git] / reactos / 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 struct AutomationObject AutomationObject;
51
52 struct 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 (*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 (*funcFree)(AutomationObject* This);
84 };
85
86 /*
87 * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
88 */
89
90 typedef struct {
91 IEnumVARIANT IEnumVARIANT_iface;
92 LONG ref;
93
94 /* Current position and pointer to AutomationObject that stores actual data */
95 ULONG ulPos;
96 AutomationObject *pObj;
97 } ListEnumerator;
98
99 /*
100 * Structures for additional data required by specific automation objects
101 */
102
103 typedef struct {
104 ULONG ulCount;
105 VARIANT *pVars;
106 } ListData;
107
108 typedef struct {
109 /* The parent Installer object */
110 IDispatch *pInstaller;
111 } SessionData;
112
113 /* VTables */
114 static const struct IDispatchVtbl AutomationObject_Vtbl;
115 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
116 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl;
117
118 /* Load type info so we don't have to process GetIDsOfNames */
119 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
120 {
121 HRESULT hr;
122 LPTYPELIB pLib = NULL;
123 LPTYPEINFO pInfo = NULL;
124 static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
125
126 TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
127
128 /* Load registered type library */
129 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
130 if (FAILED(hr)) {
131 hr = LoadTypeLib(szMsiServer, &pLib);
132 if (FAILED(hr)) {
133 ERR("Could not load msiserver.tlb\n");
134 return hr;
135 }
136 }
137
138 /* Get type information for object */
139 hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
140 ITypeLib_Release(pLib);
141 if (FAILED(hr)) {
142 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
143 return hr;
144 }
145 *pptinfo = pInfo;
146 return S_OK;
147 }
148
149 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
150 * with the appropriate clsid and invocation function. */
151 static HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, void **ppObj, REFIID clsid,
152 HRESULT (*funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*),
153 void (*funcFree)(AutomationObject*), SIZE_T sizetPrivateData)
154 {
155 AutomationObject *object;
156 HRESULT hr;
157
158 TRACE("(%d,%p,%p,%s,%p,%p,%ld)\n", msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
159
160 if( pUnkOuter )
161 return CLASS_E_NOAGGREGATION;
162
163 object = msi_alloc_zero( sizeof(AutomationObject) + sizetPrivateData );
164
165 /* Set all the VTable references */
166 object->lpVtbl = &AutomationObject_Vtbl;
167 object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
168 object->ref = 1;
169
170 /* Store data that was passed */
171 object->msiHandle = msiHandle;
172 object->clsid = (LPCLSID)clsid;
173 object->funcInvoke = funcInvoke;
174 object->funcFree = funcFree;
175
176 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
177 object->iTypeInfo = NULL;
178 hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
179 if (FAILED(hr)) {
180 msi_free( object );
181 return hr;
182 }
183
184 *ppObj = object;
185
186 return S_OK;
187 }
188
189 /* Create a list enumerator, placing the result in the pointer ppObj. */
190 static HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos)
191 {
192 ListEnumerator *object;
193
194 TRACE("(%p,%p,%p,%uld)\n", pUnkOuter, ppObj, pObj, ulPos);
195
196 if( pUnkOuter )
197 return CLASS_E_NOAGGREGATION;
198
199 object = msi_alloc_zero( sizeof(ListEnumerator) );
200
201 /* Set all the VTable references */
202 object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
203 object->ref = 1;
204
205 /* Store data that was passed */
206 object->ulPos = ulPos;
207 object->pObj = pObj;
208 if (pObj) IDispatch_AddRef((IDispatch *)pObj);
209
210 *ppObj = object;
211 return S_OK;
212 }
213
214 /* Macros to get pointer to AutomationObject from the other VTables. */
215 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
216 {
217 return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
218 }
219
220 /* Macro to get pointer to private object data */
221 static inline void *private_data( AutomationObject *This )
222 {
223 return This + 1;
224 }
225
226 /*
227 * AutomationObject methods
228 */
229
230 /*** IUnknown methods ***/
231 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
232 {
233 AutomationObject *This = (AutomationObject *)iface;
234
235 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
236
237 if (ppvObject == NULL)
238 return E_INVALIDARG;
239
240 *ppvObject = 0;
241
242 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
243 *ppvObject = This;
244 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
245 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
246 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
247 *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
248 else
249 {
250 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
251 return E_NOINTERFACE;
252 }
253
254 /*
255 * Query Interface always increases the reference count by one when it is
256 * successful
257 */
258 IClassFactory_AddRef(iface);
259
260 return S_OK;
261 }
262
263 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
264 {
265 AutomationObject *This = (AutomationObject *)iface;
266
267 TRACE("(%p/%p)\n", iface, This);
268
269 return InterlockedIncrement(&This->ref);
270 }
271
272 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
273 {
274 AutomationObject *This = (AutomationObject *)iface;
275 ULONG ref = InterlockedDecrement(&This->ref);
276
277 TRACE("(%p/%p)\n", iface, This);
278
279 if (!ref)
280 {
281 if (This->funcFree) This->funcFree(This);
282 ITypeInfo_Release(This->iTypeInfo);
283 MsiCloseHandle(This->msiHandle);
284 msi_free(This);
285 }
286
287 return ref;
288 }
289
290 /*** IDispatch methods ***/
291 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
292 IDispatch* iface,
293 UINT* pctinfo)
294 {
295 AutomationObject *This = (AutomationObject *)iface;
296
297 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
298 *pctinfo = 1;
299 return S_OK;
300 }
301
302 static HRESULT WINAPI AutomationObject_GetTypeInfo(
303 IDispatch* iface,
304 UINT iTInfo,
305 LCID lcid,
306 ITypeInfo** ppTInfo)
307 {
308 AutomationObject *This = (AutomationObject *)iface;
309 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
310
311 ITypeInfo_AddRef(This->iTypeInfo);
312 *ppTInfo = This->iTypeInfo;
313 return S_OK;
314 }
315
316 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
317 IDispatch* iface,
318 REFIID riid,
319 LPOLESTR* rgszNames,
320 UINT cNames,
321 LCID lcid,
322 DISPID* rgDispId)
323 {
324 AutomationObject *This = (AutomationObject *)iface;
325 HRESULT hr;
326 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
327
328 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
329 hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
330 if (hr == DISP_E_UNKNOWNNAME)
331 {
332 UINT idx;
333 for (idx=0; idx<cNames; idx++)
334 {
335 if (rgDispId[idx] == DISPID_UNKNOWN)
336 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
337 }
338 }
339 return hr;
340 }
341
342 /* Maximum number of allowed function parameters+1 */
343 #define MAX_FUNC_PARAMS 20
344
345 /* Some error checking is done here to simplify individual object function invocation */
346 static HRESULT WINAPI AutomationObject_Invoke(
347 IDispatch* iface,
348 DISPID dispIdMember,
349 REFIID riid,
350 LCID lcid,
351 WORD wFlags,
352 DISPPARAMS* pDispParams,
353 VARIANT* pVarResult,
354 EXCEPINFO* pExcepInfo,
355 UINT* puArgErr)
356 {
357 AutomationObject *This = (AutomationObject *)iface;
358 HRESULT hr;
359 unsigned int uArgErr;
360 VARIANT varResultDummy;
361 BSTR bstrName = NULL;
362
363 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
364
365 if (!IsEqualIID(riid, &IID_NULL))
366 {
367 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
368 return DISP_E_UNKNOWNNAME;
369 }
370
371 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
372 {
373 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
374 return DISP_E_PARAMNOTOPTIONAL;
375 }
376
377 /* This simplifies our individual object invocation functions */
378 if (puArgErr == NULL) puArgErr = &uArgErr;
379 if (pVarResult == NULL) pVarResult = &varResultDummy;
380
381 /* Assume return type is void unless determined otherwise */
382 VariantInit(pVarResult);
383
384 /* If we are tracing, we want to see the name of the member we are invoking */
385 if (TRACE_ON(msi))
386 {
387 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
388 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
389 }
390
391 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
392
393 if (hr == DISP_E_MEMBERNOTFOUND) {
394 if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
395 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
396 }
397 else if (pExcepInfo &&
398 (hr == DISP_E_PARAMNOTFOUND ||
399 hr == DISP_E_EXCEPTION)) {
400 static const WCHAR szComma[] = { ',',0 };
401 static const WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
402 WCHAR szExceptionDescription[MAX_PATH];
403 BSTR bstrParamNames[MAX_FUNC_PARAMS];
404 unsigned namesNo, i;
405 BOOL bFirst = TRUE;
406
407 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
408 MAX_FUNC_PARAMS, &namesNo)))
409 {
410 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
411 }
412 else
413 {
414 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
415 for (i=0; i<namesNo; i++)
416 {
417 if (bFirst) bFirst = FALSE;
418 else {
419 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
420 }
421 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
422 SysFreeString(bstrParamNames[i]);
423 }
424
425 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
426 pExcepInfo->wCode = 1000;
427 pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
428 pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
429 hr = DISP_E_EXCEPTION;
430 }
431 }
432
433 /* Make sure we free the return variant if it is our dummy variant */
434 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
435
436 /* Free function name if we retrieved it */
437 SysFreeString(bstrName);
438
439 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
440
441 return hr;
442 }
443
444 static const struct IDispatchVtbl AutomationObject_Vtbl =
445 {
446 AutomationObject_QueryInterface,
447 AutomationObject_AddRef,
448 AutomationObject_Release,
449 AutomationObject_GetTypeInfoCount,
450 AutomationObject_GetTypeInfo,
451 AutomationObject_GetIDsOfNames,
452 AutomationObject_Invoke
453 };
454
455 /*
456 * IProvideMultipleClassInfo methods
457 */
458
459 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
460 IProvideMultipleClassInfo* iface,
461 REFIID riid,
462 VOID** ppvoid)
463 {
464 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
465 return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
466 }
467
468 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
469 {
470 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
471 return AutomationObject_AddRef((IDispatch *)This);
472 }
473
474 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
475 {
476 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
477 return AutomationObject_Release((IDispatch *)This);
478 }
479
480 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
481 {
482 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
483 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
484 return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
485 }
486
487 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
488 {
489 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
490 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
491
492 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
493 return E_INVALIDARG;
494 else {
495 *pGUID = *This->clsid;
496 return S_OK;
497 }
498 }
499
500 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
501 {
502 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
503
504 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
505 *pcti = 1;
506 return S_OK;
507 }
508
509 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
510 ULONG iti,
511 DWORD dwFlags,
512 ITypeInfo** pptiCoClass,
513 DWORD* pdwTIFlags,
514 ULONG* pcdispidReserved,
515 IID* piidPrimary,
516 IID* piidSource)
517 {
518 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
519
520 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
521
522 if (iti != 0)
523 return E_INVALIDARG;
524
525 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
526 load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
527
528 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
529 {
530 *pdwTIFlags = 0;
531 *pcdispidReserved = 0;
532 }
533
534 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
535 *piidPrimary = *This->clsid;
536 }
537
538 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
539 *piidSource = *This->clsid;
540 }
541
542 return S_OK;
543 }
544
545 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
546 {
547 AutomationObject_IProvideMultipleClassInfo_QueryInterface,
548 AutomationObject_IProvideMultipleClassInfo_AddRef,
549 AutomationObject_IProvideMultipleClassInfo_Release,
550 AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
551 AutomationObject_IProvideMultipleClassInfo_GetGUID,
552 AutomationObject_GetMultiTypeInfoCount,
553 AutomationObject_GetInfoOfIndex
554 };
555
556 /*
557 * ListEnumerator methods
558 */
559
560 static inline ListEnumerator *impl_from_IEnumVARIANT(IEnumVARIANT* iface)
561 {
562 return CONTAINING_RECORD(iface, ListEnumerator, IEnumVARIANT_iface);
563 }
564
565 /*** IUnknown methods ***/
566 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid,
567 void** ppvObject)
568 {
569 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
570
571 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
572
573 if (ppvObject == NULL)
574 return E_INVALIDARG;
575
576 *ppvObject = 0;
577
578 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT))
579 *ppvObject = This;
580 else
581 {
582 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
583 return E_NOINTERFACE;
584 }
585
586 IClassFactory_AddRef(iface);
587 return S_OK;
588 }
589
590 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
591 {
592 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
593
594 TRACE("(%p/%p)\n", iface, This);
595
596 return InterlockedIncrement(&This->ref);
597 }
598
599 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
600 {
601 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
602 ULONG ref = InterlockedDecrement(&This->ref);
603
604 TRACE("(%p/%p)\n", iface, This);
605
606 if (!ref)
607 {
608 if (This->pObj) IDispatch_Release((IDispatch *)This->pObj);
609 msi_free(This);
610 }
611
612 return ref;
613 }
614
615 /* IEnumVARIANT methods */
616
617 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar,
618 ULONG* pCeltFetched)
619 {
620 ListEnumerator *This = impl_from_IEnumVARIANT(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 = impl_from_IEnumVARIANT(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 = impl_from_IEnumVARIANT(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 = impl_from_IEnumVARIANT(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 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 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 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 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 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 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 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 /* fall through */
1514 case REG_SZ:
1515 V_VT(pVarResult) = VT_BSTR;
1516 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1517 break;
1518
1519 case REG_EXPAND_SZ:
1520 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1521 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1522 else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1523 ERR("Out of memory\n");
1524 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1525 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1526 else
1527 {
1528 V_VT(pVarResult) = VT_BSTR;
1529 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1530 }
1531 msi_free(szNewString);
1532 break;
1533
1534 case REG_DWORD:
1535 V_VT(pVarResult) = VT_I4;
1536 V_I4(pVarResult) = *((DWORD *)lpData);
1537 break;
1538
1539 case REG_QWORD:
1540 V_VT(pVarResult) = VT_BSTR;
1541 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1542 break;
1543
1544 case REG_BINARY:
1545 V_VT(pVarResult) = VT_BSTR;
1546 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1547 break;
1548
1549 case REG_NONE:
1550 V_VT(pVarResult) = VT_EMPTY;
1551 break;
1552
1553 default:
1554 FIXME("Unhandled registry value type %d\n", dwType);
1555 }
1556 }
1557
1558 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1559 DISPPARAMS* pDispParams,
1560 VARIANT* pVarResult,
1561 EXCEPINFO* pExcepInfo,
1562 UINT* puArgErr)
1563 {
1564 HRESULT hr;
1565 VARIANTARG varg0;
1566 MSIHANDLE hrec;
1567 IDispatch* dispatch;
1568
1569 if (!(wFlags & DISPATCH_METHOD))
1570 return DISP_E_MEMBERNOTFOUND;
1571
1572 VariantInit(&varg0);
1573 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1574 if (FAILED(hr))
1575 return hr;
1576
1577 V_VT(pVarResult) = VT_DISPATCH;
1578
1579 hrec = MsiCreateRecord(V_I4(&varg0));
1580 if (!hrec)
1581 return DISP_E_EXCEPTION;
1582
1583 hr = create_automation_object(hrec, NULL, (LPVOID*)&dispatch,
1584 &DIID_Record, RecordImpl_Invoke, NULL, 0);
1585 if (SUCCEEDED(hr))
1586 V_DISPATCH(pVarResult) = dispatch;
1587
1588 return hr;
1589 }
1590
1591 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1592 WORD wFlags,
1593 DISPPARAMS* pDispParams,
1594 VARIANT* pVarResult,
1595 EXCEPINFO* pExcepInfo,
1596 UINT* puArgErr)
1597 {
1598 UINT ret;
1599 HRESULT hr;
1600 MSIHANDLE hpkg;
1601 IDispatch* dispatch;
1602 VARIANTARG varg0, varg1;
1603
1604 if (!(wFlags & DISPATCH_METHOD))
1605 return DISP_E_MEMBERNOTFOUND;
1606
1607 if (pDispParams->cArgs == 0)
1608 return DISP_E_TYPEMISMATCH;
1609
1610 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1611 return DISP_E_TYPEMISMATCH;
1612
1613 VariantInit(&varg0);
1614 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1615 if (FAILED(hr))
1616 return hr;
1617
1618 VariantInit(&varg1);
1619 if (pDispParams->cArgs == 2)
1620 {
1621 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1622 if (FAILED(hr))
1623 goto done;
1624 }
1625 else
1626 {
1627 V_VT(&varg1) = VT_I4;
1628 V_I4(&varg1) = 0;
1629 }
1630
1631 V_VT(pVarResult) = VT_DISPATCH;
1632
1633 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1634 if (ret != ERROR_SUCCESS)
1635 {
1636 hr = DISP_E_EXCEPTION;
1637 goto done;
1638 }
1639
1640 hr = create_session(hpkg, (IDispatch *)This, &dispatch);
1641 if (SUCCEEDED(hr))
1642 V_DISPATCH(pVarResult) = dispatch;
1643
1644 done:
1645 VariantClear(&varg0);
1646 VariantClear(&varg1);
1647 return hr;
1648 }
1649
1650 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1651 DISPPARAMS* pDispParams,
1652 VARIANT* pVarResult,
1653 EXCEPINFO* pExcepInfo,
1654 UINT* puArgErr)
1655 {
1656 HRESULT hr;
1657 VARIANTARG varg0;
1658
1659 if (!(wFlags & DISPATCH_METHOD))
1660 return DISP_E_MEMBERNOTFOUND;
1661
1662 VariantInit(&varg0);
1663 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1664 if (FAILED(hr))
1665 return hr;
1666
1667 FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1668
1669 VariantInit(pVarResult);
1670
1671 VariantClear(&varg0);
1672 return S_OK;
1673 }
1674
1675 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1676 DISPPARAMS* pDispParams,
1677 VARIANT* pVarResult,
1678 EXCEPINFO* pExcepInfo,
1679 UINT* puArgErr)
1680 {
1681 UINT ret;
1682 HRESULT hr;
1683 MSIHANDLE hdb;
1684 IDispatch* dispatch;
1685 VARIANTARG varg0, varg1;
1686
1687 if (!(wFlags & DISPATCH_METHOD))
1688 return DISP_E_MEMBERNOTFOUND;
1689
1690 VariantInit(&varg0);
1691 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1692 if (FAILED(hr))
1693 return hr;
1694
1695 VariantInit(&varg1);
1696 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1697 if (FAILED(hr))
1698 goto done;
1699
1700 V_VT(pVarResult) = VT_DISPATCH;
1701
1702 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1703 if (ret != ERROR_SUCCESS)
1704 {
1705 hr = DISP_E_EXCEPTION;
1706 goto done;
1707 }
1708
1709 hr = create_automation_object(hdb, NULL, (LPVOID *)&dispatch,
1710 &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1711 if (SUCCEEDED(hr))
1712 V_DISPATCH(pVarResult) = dispatch;
1713
1714 done:
1715 VariantClear(&varg0);
1716 VariantClear(&varg1);
1717 return hr;
1718 }
1719
1720 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1721 DISPPARAMS* pDispParams,
1722 VARIANT* pVarResult,
1723 EXCEPINFO* pExcepInfo,
1724 UINT* puArgErr)
1725 {
1726 if (!(wFlags & DISPATCH_METHOD))
1727 return DISP_E_MEMBERNOTFOUND;
1728
1729 FIXME("\n");
1730
1731 VariantInit(pVarResult);
1732 return S_OK;
1733 }
1734
1735 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1736 DISPPARAMS* pDispParams,
1737 VARIANT* pVarResult,
1738 EXCEPINFO* pExcepInfo,
1739 UINT* puArgErr)
1740 {
1741 HRESULT hr;
1742 VARIANTARG varg0;
1743 INSTALLUILEVEL ui;
1744
1745 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1746 return DISP_E_MEMBERNOTFOUND;
1747
1748 if (wFlags & DISPATCH_PROPERTYPUT)
1749 {
1750 VariantInit(&varg0);
1751 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1752 if (FAILED(hr))
1753 return hr;
1754
1755 ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1756 if (ui == INSTALLUILEVEL_NOCHANGE)
1757 return DISP_E_EXCEPTION;
1758 }
1759 else if (wFlags & DISPATCH_PROPERTYGET)
1760 {
1761 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1762 if (ui == INSTALLUILEVEL_NOCHANGE)
1763 return DISP_E_EXCEPTION;
1764
1765 V_VT(pVarResult) = VT_I4;
1766 V_I4(pVarResult) = ui;
1767 }
1768
1769 return S_OK;
1770 }
1771
1772 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1773 DISPPARAMS* pDispParams,
1774 VARIANT* pVarResult,
1775 EXCEPINFO* pExcepInfo,
1776 UINT* puArgErr)
1777 {
1778 if (!(wFlags & DISPATCH_METHOD))
1779 return DISP_E_MEMBERNOTFOUND;
1780
1781 FIXME("\n");
1782
1783 VariantInit(pVarResult);
1784 return S_OK;
1785 }
1786
1787 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1788 DISPPARAMS* pDispParams,
1789 VARIANT* pVarResult,
1790 EXCEPINFO* pExcepInfo,
1791 UINT* puArgErr)
1792 {
1793 UINT ret;
1794 HRESULT hr;
1795 VARIANTARG varg0, varg1;
1796
1797 if (!(wFlags & DISPATCH_METHOD))
1798 return DISP_E_MEMBERNOTFOUND;
1799
1800 VariantInit(&varg0);
1801 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1802 if (FAILED(hr))
1803 return hr;
1804
1805 VariantInit(&varg1);
1806 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1807 if (FAILED(hr))
1808 goto done;
1809
1810 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1811 if (ret != ERROR_SUCCESS)
1812 {
1813 hr = DISP_E_EXCEPTION;
1814 goto done;
1815 }
1816
1817 done:
1818 VariantClear(&varg0);
1819 VariantClear(&varg1);
1820 return hr;
1821 }
1822
1823 static HRESULT InstallerImpl_Version(WORD wFlags,
1824 VARIANT* pVarResult,
1825 EXCEPINFO* pExcepInfo,
1826 UINT* puArgErr)
1827 {
1828 HRESULT hr;
1829 DLLVERSIONINFO verinfo;
1830 WCHAR version[MAX_PATH];
1831
1832 static const WCHAR format[] = {
1833 '%','d','.','%','d','.','%','d','.','%','d',0};
1834
1835 if (!(wFlags & DISPATCH_PROPERTYGET))
1836 return DISP_E_MEMBERNOTFOUND;
1837
1838 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1839 hr = DllGetVersion(&verinfo);
1840 if (FAILED(hr))
1841 return hr;
1842
1843 sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1844 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1845
1846 V_VT(pVarResult) = VT_BSTR;
1847 V_BSTR(pVarResult) = SysAllocString(version);
1848 return S_OK;
1849 }
1850
1851 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1852 DISPPARAMS* pDispParams,
1853 VARIANT* pVarResult,
1854 EXCEPINFO* pExcepInfo,
1855 UINT* puArgErr)
1856 {
1857 if (!(wFlags & DISPATCH_METHOD))
1858 return DISP_E_MEMBERNOTFOUND;
1859
1860 FIXME("\n");
1861
1862 VariantInit(pVarResult);
1863 return S_OK;
1864 }
1865
1866 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1867 DISPPARAMS* pDispParams,
1868 VARIANT* pVarResult,
1869 EXCEPINFO* pExcepInfo,
1870 UINT* puArgErr)
1871 {
1872 UINT ret;
1873 HKEY hkey = NULL;
1874 HRESULT hr;
1875 UINT posValue;
1876 DWORD type, size;
1877 LPWSTR szString = NULL;
1878 VARIANTARG varg0, varg1, varg2;
1879
1880 if (!(wFlags & DISPATCH_METHOD))
1881 return DISP_E_MEMBERNOTFOUND;
1882
1883 VariantInit(&varg0);
1884 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1885 if (FAILED(hr))
1886 return hr;
1887
1888 VariantInit(&varg1);
1889 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1890 if (FAILED(hr))
1891 goto done;
1892
1893 /* Save valuePos so we can save puArgErr if we are unable to do our type
1894 * conversions.
1895 */
1896 posValue = 2;
1897 VariantInit(&varg2);
1898 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1899 if (FAILED(hr))
1900 goto done;
1901
1902 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
1903 V_I4(&varg0) <= REG_INDEX_DYN_DATA)
1904 {
1905 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
1906 }
1907
1908 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1909
1910 /* Only VT_EMPTY case can do anything if the key doesn't exist. */
1911 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
1912 {
1913 hr = DISP_E_BADINDEX;
1914 goto done;
1915 }
1916
1917 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1918 switch (V_VT(&varg2))
1919 {
1920 /* Return VT_BOOL clarifying whether registry key exists or not. */
1921 case VT_EMPTY:
1922 V_VT(pVarResult) = VT_BOOL;
1923 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1924 break;
1925
1926 /* Return the value of specified key if it exists. */
1927 case VT_BSTR:
1928 ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
1929 NULL, NULL, NULL, &size);
1930 if (ret != ERROR_SUCCESS)
1931 {
1932 hr = DISP_E_BADINDEX;
1933 goto done;
1934 }
1935
1936 szString = msi_alloc(size);
1937 if (!szString)
1938 {
1939 hr = E_OUTOFMEMORY;
1940 goto done;
1941 }
1942
1943 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
1944 &type, (LPBYTE)szString, &size);
1945 if (ret != ERROR_SUCCESS)
1946 {
1947 msi_free(szString);
1948 hr = DISP_E_BADINDEX;
1949 goto done;
1950 }
1951
1952 variant_from_registry_value(pVarResult, type,
1953 (LPBYTE)szString, size);
1954 msi_free(szString);
1955 break;
1956
1957 /* Try to make it into VT_I4, can use VariantChangeType for this. */
1958 default:
1959 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1960 if (FAILED(hr))
1961 {
1962 if (hr == DISP_E_TYPEMISMATCH)
1963 *puArgErr = posValue;
1964
1965 goto done;
1966 }
1967
1968 /* Retrieve class name or maximum value name or subkey name size. */
1969 if (!V_I4(&varg2))
1970 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
1971 NULL, NULL, NULL, NULL, NULL, NULL);
1972 else if (V_I4(&varg2) > 0)
1973 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
1974 NULL, NULL, &size, NULL, NULL, NULL);
1975 else /* V_I4(&varg2) < 0 */
1976 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
1977 NULL, NULL, NULL, NULL, NULL, NULL);
1978
1979 if (ret != ERROR_SUCCESS)
1980 goto done;
1981
1982 szString = msi_alloc(++size * sizeof(WCHAR));
1983 if (!szString)
1984 {
1985 hr = E_OUTOFMEMORY;
1986 goto done;
1987 }
1988
1989 if (!V_I4(&varg2))
1990 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
1991 NULL, NULL, NULL, NULL, NULL, NULL);
1992 else if (V_I4(&varg2) > 0)
1993 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
1994 &size, 0, 0, NULL, NULL);
1995 else /* V_I4(&varg2) < 0 */
1996 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
1997
1998 if (ret == ERROR_SUCCESS)
1999 {
2000 V_VT(pVarResult) = VT_BSTR;
2001 V_BSTR(pVarResult) = SysAllocString(szString);
2002 }
2003
2004 msi_free(szString);
2005 }
2006
2007 done:
2008 VariantClear(&varg0);
2009 VariantClear(&varg1);
2010 VariantClear(&varg2);
2011 RegCloseKey(hkey);
2012 return hr;
2013 }
2014
2015 static HRESULT InstallerImpl_Environment(WORD wFlags,
2016 DISPPARAMS* pDispParams,
2017 VARIANT* pVarResult,
2018 EXCEPINFO* pExcepInfo,
2019 UINT* puArgErr)
2020 {
2021 if (!(wFlags & DISPATCH_METHOD))
2022 return DISP_E_MEMBERNOTFOUND;
2023
2024 FIXME("\n");
2025
2026 VariantInit(pVarResult);
2027 return S_OK;
2028 }
2029
2030 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2031 DISPPARAMS* pDispParams,
2032 VARIANT* pVarResult,
2033 EXCEPINFO* pExcepInfo,
2034 UINT* puArgErr)
2035 {
2036 if (!(wFlags & DISPATCH_METHOD))
2037 return DISP_E_MEMBERNOTFOUND;
2038
2039 FIXME("\n");
2040
2041 VariantInit(pVarResult);
2042 return S_OK;
2043 }
2044
2045 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2046 DISPPARAMS* pDispParams,
2047 VARIANT* pVarResult,
2048 EXCEPINFO* pExcepInfo,
2049 UINT* puArgErr)
2050 {
2051 if (!(wFlags & DISPATCH_METHOD))
2052 return DISP_E_MEMBERNOTFOUND;
2053
2054 FIXME("\n");
2055
2056 VariantInit(pVarResult);
2057 return S_OK;
2058 }
2059
2060 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2061 DISPPARAMS* pDispParams,
2062 VARIANT* pVarResult,
2063 EXCEPINFO* pExcepInfo,
2064 UINT* puArgErr)
2065 {
2066 if (!(wFlags & DISPATCH_METHOD))
2067 return DISP_E_MEMBERNOTFOUND;
2068
2069 FIXME("\n");
2070
2071 VariantInit(pVarResult);
2072 return S_OK;
2073 }
2074
2075 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2076 DISPPARAMS* pDispParams,
2077 VARIANT* pVarResult,
2078 EXCEPINFO* pExcepInfo,
2079 UINT* puArgErr)
2080 {
2081 HRESULT hr;
2082 VARIANTARG varg0;
2083
2084 if (!(wFlags & DISPATCH_PROPERTYGET))
2085 return DISP_E_MEMBERNOTFOUND;
2086
2087 VariantInit(&varg0);
2088 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2089 if (FAILED(hr))
2090 return hr;
2091
2092 V_VT(pVarResult) = VT_I4;
2093 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2094
2095 VariantClear(&varg0);
2096 return S_OK;
2097 }
2098
2099 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2100 DISPPARAMS* pDispParams,
2101 VARIANT* pVarResult,
2102 EXCEPINFO* pExcepInfo,
2103 UINT* puArgErr)
2104 {
2105 UINT ret;
2106 HRESULT hr;
2107 DWORD size;
2108 LPWSTR str = NULL;
2109 VARIANTARG varg0, varg1;
2110
2111 if (!(wFlags & DISPATCH_PROPERTYGET))
2112 return DISP_E_MEMBERNOTFOUND;
2113
2114 VariantInit(&varg0);
2115 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2116 if (FAILED(hr))
2117 return hr;
2118
2119 VariantInit(&varg1);
2120 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2121 if (FAILED(hr))
2122 goto done;
2123
2124 V_VT(pVarResult) = VT_BSTR;
2125 V_BSTR(pVarResult) = NULL;
2126
2127 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2128 if (ret != ERROR_SUCCESS)
2129 {
2130 hr = DISP_E_EXCEPTION;
2131 goto done;
2132 }
2133
2134 str = msi_alloc(++size * sizeof(WCHAR));
2135 if (!str)
2136 {
2137 hr = E_OUTOFMEMORY;
2138 goto done;
2139 }
2140
2141 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2142 if (ret != ERROR_SUCCESS)
2143 {
2144 hr = DISP_E_EXCEPTION;
2145 goto done;
2146 }
2147
2148 V_BSTR(pVarResult) = SysAllocString(str);
2149 hr = S_OK;
2150
2151 done:
2152 msi_free(str);
2153 VariantClear(&varg0);
2154 VariantClear(&varg1);
2155 return hr;
2156 }
2157
2158 static void cleanup_products(IDispatch* dispatch, ULONG count)
2159 {
2160 UINT i;
2161 ListData* ldata = private_data((AutomationObject *)dispatch);
2162
2163 for (i = 0; i < count - 1; i++)
2164 VariantClear(&ldata->pVars[i]);
2165
2166 ldata->ulCount = 0;
2167 msi_free(ldata->pVars);
2168
2169 IDispatch_Release(dispatch);
2170 }
2171
2172 static HRESULT InstallerImpl_Products(WORD wFlags,
2173 DISPPARAMS* pDispParams,
2174 VARIANT* pVarResult,
2175 EXCEPINFO* pExcepInfo,
2176 UINT* puArgErr)
2177 {
2178 UINT ret;
2179 HRESULT hr;
2180 ULONG idx = 0;
2181 ListData *ldata;
2182 IDispatch *dispatch;
2183 WCHAR product[GUID_SIZE];
2184
2185 if (!(wFlags & DISPATCH_PROPERTYGET))
2186 return DISP_E_MEMBERNOTFOUND;
2187
2188 /* Find number of products. */
2189 while ((ret = MsiEnumProductsW(idx, product)) == ERROR_SUCCESS)
2190 idx++;
2191
2192 if (ret != ERROR_NO_MORE_ITEMS)
2193 return DISP_E_EXCEPTION;
2194
2195 V_VT(pVarResult) = VT_DISPATCH;
2196 hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2197 &DIID_StringList, ListImpl_Invoke,
2198 ListImpl_Free, sizeof(ListData));
2199 if (FAILED(hr))
2200 return hr;
2201
2202 V_DISPATCH(pVarResult) = dispatch;
2203
2204 /* Save product strings. */
2205 ldata = private_data((AutomationObject *)dispatch);
2206 ldata->ulCount = 0;
2207 ldata->pVars = msi_alloc_zero(sizeof(VARIANT) * idx);
2208 if (!ldata->pVars)
2209 {
2210 IDispatch_Release(dispatch);
2211 return E_OUTOFMEMORY;
2212 }
2213
2214 ldata->ulCount = idx;
2215 for (idx = 0; idx < ldata->ulCount; idx++)
2216 {
2217 ret = MsiEnumProductsW(idx, product);
2218 if (ret != ERROR_SUCCESS)
2219 {
2220 cleanup_products(dispatch, idx - 1);
2221 return DISP_E_EXCEPTION;
2222 }
2223
2224 VariantInit(&ldata->pVars[idx]);
2225 V_VT(&ldata->pVars[idx]) = VT_BSTR;
2226 V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2227 }
2228
2229 return S_OK;
2230 }
2231
2232 static HRESULT InstallerImpl_RelatedProducts(WORD wFlags,
2233 DISPPARAMS* pDispParams,
2234 VARIANT* pVarResult,
2235 EXCEPINFO* pExcepInfo,
2236 UINT* puArgErr)
2237 {
2238 UINT ret;
2239 ULONG idx;
2240 HRESULT hr;
2241 ListData *ldata;
2242 VARIANTARG varg0;
2243 IDispatch* dispatch;
2244 WCHAR product[GUID_SIZE];
2245
2246 if (!(wFlags & DISPATCH_PROPERTYGET))
2247 return DISP_E_MEMBERNOTFOUND;
2248
2249 VariantInit(&varg0);
2250 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2251 if (FAILED(hr))
2252 return hr;
2253
2254 /* Find number of related products. */
2255 idx = 0;
2256 do
2257 {
2258 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2259 if (ret == ERROR_SUCCESS)
2260 idx++;
2261 } while (ret == ERROR_SUCCESS);
2262
2263 if (ret != ERROR_NO_MORE_ITEMS)
2264 {
2265 hr = DISP_E_EXCEPTION;
2266 goto done;
2267 }
2268
2269 V_VT(pVarResult) = VT_DISPATCH;
2270
2271 hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2272 &DIID_StringList, ListImpl_Invoke,
2273 ListImpl_Free, sizeof(ListData));
2274 if (FAILED(hr))
2275 goto done;
2276
2277 V_DISPATCH(pVarResult) = dispatch;
2278
2279 /* Save product strings. */
2280 ldata = private_data((AutomationObject *)dispatch);
2281 ldata->pVars = msi_alloc(sizeof(VARIANT) * idx);
2282 if (!ldata->pVars)
2283 {
2284 IDispatch_Release(dispatch);
2285 hr = E_OUTOFMEMORY;
2286 goto done;
2287 }
2288
2289 ldata->ulCount = idx;
2290 for (idx = 0; idx < ldata->ulCount; idx++)
2291 {
2292 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2293 if (ret != ERROR_SUCCESS)
2294 {
2295 cleanup_products(dispatch, idx - 1);
2296 hr = DISP_E_EXCEPTION;
2297 goto done;
2298 }
2299
2300 VariantInit(&ldata->pVars[idx]);
2301 V_VT(&ldata->pVars[idx]) = VT_BSTR;
2302 V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2303 }
2304
2305 hr = S_OK;
2306
2307 done:
2308 VariantClear(&varg0);
2309 return hr;
2310 }
2311
2312 static HRESULT InstallerImpl_Invoke(
2313 AutomationObject* This,
2314 DISPID dispIdMember,
2315 REFIID riid,
2316 LCID lcid,
2317 WORD wFlags,
2318 DISPPARAMS* pDispParams,
2319 VARIANT* pVarResult,
2320 EXCEPINFO* pExcepInfo,
2321 UINT* puArgErr)
2322 {
2323 switch (dispIdMember)
2324 {
2325 case DISPID_INSTALLER_CREATERECORD:
2326 return InstallerImpl_CreateRecord(wFlags, pDispParams,
2327 pVarResult, pExcepInfo, puArgErr);
2328
2329 case DISPID_INSTALLER_OPENPACKAGE:
2330 return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2331 pVarResult, pExcepInfo, puArgErr);
2332
2333 case DISPID_INSTALLER_OPENPRODUCT:
2334 return InstallerImpl_OpenProduct(wFlags, pDispParams,
2335 pVarResult, pExcepInfo, puArgErr);
2336
2337 case DISPID_INSTALLER_OPENDATABASE:
2338 return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2339 pVarResult, pExcepInfo, puArgErr);
2340
2341 case DISPID_INSTALLER_SUMMARYINFORMATION:
2342 return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2343 pVarResult, pExcepInfo,
2344 puArgErr);
2345
2346 case DISPID_INSTALLER_UILEVEL:
2347 return InstallerImpl_UILevel(wFlags, pDispParams,
2348 pVarResult, pExcepInfo, puArgErr);
2349
2350 case DISPID_INSTALLER_ENABLELOG:
2351 return InstallerImpl_EnableLog(wFlags, pDispParams,
2352 pVarResult, pExcepInfo, puArgErr);
2353
2354 case DISPID_INSTALLER_INSTALLPRODUCT:
2355 return InstallerImpl_InstallProduct(wFlags, pDispParams,
2356 pVarResult, pExcepInfo,
2357 puArgErr);
2358
2359 case DISPID_INSTALLER_VERSION:
2360 return InstallerImpl_Version(wFlags, pVarResult,
2361 pExcepInfo, puArgErr);
2362
2363 case DISPID_INSTALLER_LASTERRORRECORD:
2364 return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2365 pVarResult, pExcepInfo,
2366 puArgErr);
2367
2368 case DISPID_INSTALLER_REGISTRYVALUE:
2369 return InstallerImpl_RegistryValue(wFlags, pDispParams,
2370 pVarResult, pExcepInfo,
2371 puArgErr);
2372
2373 case DISPID_INSTALLER_ENVIRONMENT:
2374 return InstallerImpl_Environment(wFlags, pDispParams,
2375 pVarResult, pExcepInfo, puArgErr);
2376
2377 case DISPID_INSTALLER_FILEATTRIBUTES:
2378 return InstallerImpl_FileAttributes(wFlags, pDispParams,
2379 pVarResult, pExcepInfo,
2380 puArgErr);
2381
2382 case DISPID_INSTALLER_FILESIZE:
2383 return InstallerImpl_FileSize(wFlags, pDispParams,
2384 pVarResult, pExcepInfo, puArgErr);
2385
2386 case DISPID_INSTALLER_FILEVERSION:
2387 return InstallerImpl_FileVersion(wFlags, pDispParams,
2388 pVarResult, pExcepInfo, puArgErr);
2389
2390 case DISPID_INSTALLER_PRODUCTSTATE:
2391 return InstallerImpl_ProductState(wFlags, pDispParams,
2392 pVarResult, pExcepInfo, puArgErr);
2393
2394 case DISPID_INSTALLER_PRODUCTINFO:
2395 return InstallerImpl_ProductInfo(wFlags, pDispParams,
2396 pVarResult, pExcepInfo, puArgErr);
2397
2398 case DISPID_INSTALLER_PRODUCTS:
2399 return InstallerImpl_Products(wFlags, pDispParams,
2400 pVarResult, pExcepInfo, puArgErr);
2401
2402 case DISPID_INSTALLER_RELATEDPRODUCTS:
2403 return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2404 pVarResult, pExcepInfo,
2405 puArgErr);
2406
2407 default:
2408 return DISP_E_MEMBERNOTFOUND;
2409 }
2410 }
2411
2412 /* Wrapper around create_automation_object to create an installer object. */
2413 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
2414 {
2415 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
2416 }
2417
2418 /* Wrapper around create_automation_object to create a session object. */
2419 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
2420 {
2421 HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
2422 if (SUCCEEDED(hr) && pDispatch && *pDispatch)
2423 ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
2424 return hr;
2425 }