sync msi with wine 1.1.35
[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 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 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 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 HeapFree(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 WINAPI DatabaseImpl_Invoke(
1142 AutomationObject* This,
1143 DISPID dispIdMember,
1144 REFIID riid,
1145 LCID lcid,
1146 WORD wFlags,
1147 DISPPARAMS* pDispParams,
1148 VARIANT* pVarResult,
1149 EXCEPINFO* pExcepInfo,
1150 UINT* puArgErr)
1151 {
1152 MSIHANDLE msiHandle;
1153 IDispatch *pDispatch = NULL;
1154 UINT ret;
1155 VARIANTARG varg0, varg1;
1156 HRESULT hr;
1157
1158 VariantInit(&varg0);
1159 VariantInit(&varg1);
1160
1161 switch (dispIdMember)
1162 {
1163 case DISPID_DATABASE_SUMMARYINFORMATION:
1164 if (wFlags & DISPATCH_PROPERTYGET)
1165 {
1166 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1167 if (FAILED(hr))
1168 V_I4(&varg0) = 0;
1169
1170 V_VT(pVarResult) = VT_DISPATCH;
1171 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1172 {
1173 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0);
1174 if (SUCCEEDED(hr))
1175 V_DISPATCH(pVarResult) = pDispatch;
1176 else
1177 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1178 }
1179 else
1180 {
1181 ERR("MsiGetSummaryInformation returned %d\n", ret);
1182 return DISP_E_EXCEPTION;
1183 }
1184 }
1185 else return DISP_E_MEMBERNOTFOUND;
1186 break;
1187
1188 case DISPID_DATABASE_OPENVIEW:
1189 if (wFlags & DISPATCH_METHOD)
1190 {
1191 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1192 if (FAILED(hr)) return hr;
1193 V_VT(pVarResult) = VT_DISPATCH;
1194 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1195 {
1196 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1197 V_DISPATCH(pVarResult) = pDispatch;
1198 else
1199 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1200 }
1201 else
1202 {
1203 VariantClear(&varg0);
1204 ERR("MsiDatabaseOpenView returned %d\n", ret);
1205 return DISP_E_EXCEPTION;
1206 }
1207 }
1208 else return DISP_E_MEMBERNOTFOUND;
1209 break;
1210
1211 default:
1212 return DISP_E_MEMBERNOTFOUND;
1213 }
1214
1215 VariantClear(&varg1);
1216 VariantClear(&varg0);
1217
1218 return S_OK;
1219 }
1220
1221 static HRESULT WINAPI SessionImpl_Invoke(
1222 AutomationObject* This,
1223 DISPID dispIdMember,
1224 REFIID riid,
1225 LCID lcid,
1226 WORD wFlags,
1227 DISPPARAMS* pDispParams,
1228 VARIANT* pVarResult,
1229 EXCEPINFO* pExcepInfo,
1230 UINT* puArgErr)
1231 {
1232 SessionData *data = private_data(This);
1233 WCHAR *szString;
1234 DWORD dwLen;
1235 IDispatch *pDispatch = NULL;
1236 MSIHANDLE msiHandle;
1237 LANGID langId;
1238 UINT ret;
1239 INSTALLSTATE iInstalled, iAction;
1240 VARIANTARG varg0, varg1;
1241 HRESULT hr;
1242
1243 VariantInit(&varg0);
1244 VariantInit(&varg1);
1245
1246 switch (dispIdMember)
1247 {
1248 case DISPID_SESSION_INSTALLER:
1249 if (wFlags & DISPATCH_PROPERTYGET) {
1250 V_VT(pVarResult) = VT_DISPATCH;
1251 IDispatch_AddRef(data->pInstaller);
1252 V_DISPATCH(pVarResult) = data->pInstaller;
1253 }
1254 else return DISP_E_MEMBERNOTFOUND;
1255 break;
1256
1257 case DISPID_SESSION_PROPERTY:
1258 if (wFlags & DISPATCH_PROPERTYGET) {
1259 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1260 if (FAILED(hr)) return hr;
1261 V_VT(pVarResult) = VT_BSTR;
1262 V_BSTR(pVarResult) = NULL;
1263 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1264 {
1265 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1266 ERR("Out of memory\n");
1267 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1268 V_BSTR(pVarResult) = SysAllocString(szString);
1269 msi_free(szString);
1270 }
1271 if (ret != ERROR_SUCCESS)
1272 ERR("MsiGetProperty returned %d\n", ret);
1273 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1274 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1275 if (FAILED(hr)) return hr;
1276 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1277 if (FAILED(hr)) {
1278 VariantClear(&varg0);
1279 return hr;
1280 }
1281 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1282 {
1283 VariantClear(&varg0);
1284 VariantClear(&varg1);
1285 ERR("MsiSetProperty returned %d\n", ret);
1286 return DISP_E_EXCEPTION;
1287 }
1288 }
1289 else return DISP_E_MEMBERNOTFOUND;
1290 break;
1291
1292 case DISPID_SESSION_LANGUAGE:
1293 if (wFlags & DISPATCH_PROPERTYGET) {
1294 langId = MsiGetLanguage(This->msiHandle);
1295 V_VT(pVarResult) = VT_I4;
1296 V_I4(pVarResult) = langId;
1297 }
1298 else return DISP_E_MEMBERNOTFOUND;
1299 break;
1300
1301 case DISPID_SESSION_MODE:
1302 if (wFlags & DISPATCH_PROPERTYGET) {
1303 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1304 if (FAILED(hr)) return hr;
1305 V_VT(pVarResult) = VT_BOOL;
1306 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1307 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1308 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1309 if (FAILED(hr)) return hr;
1310 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1311 if (FAILED(hr)) return hr;
1312 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1313 {
1314 ERR("MsiSetMode returned %d\n", ret);
1315 return DISP_E_EXCEPTION;
1316 }
1317 }
1318 else return DISP_E_MEMBERNOTFOUND;
1319 break;
1320
1321 case DISPID_SESSION_DATABASE:
1322 if (wFlags & DISPATCH_PROPERTYGET) {
1323 V_VT(pVarResult) = VT_DISPATCH;
1324 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1325 {
1326 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1327 V_DISPATCH(pVarResult) = pDispatch;
1328 else
1329 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1330 }
1331 else
1332 {
1333 ERR("MsiGetActiveDatabase failed\n");
1334 return DISP_E_EXCEPTION;
1335 }
1336 }
1337 else return DISP_E_MEMBERNOTFOUND;
1338 break;
1339
1340 case DISPID_SESSION_DOACTION:
1341 if (wFlags & DISPATCH_METHOD) {
1342 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1343 if (FAILED(hr)) return hr;
1344 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1345 V_VT(pVarResult) = VT_I4;
1346 switch (ret)
1347 {
1348 case ERROR_FUNCTION_NOT_CALLED:
1349 V_I4(pVarResult) = msiDoActionStatusNoAction;
1350 break;
1351 case ERROR_SUCCESS:
1352 V_I4(pVarResult) = msiDoActionStatusSuccess;
1353 break;
1354 case ERROR_INSTALL_USEREXIT:
1355 V_I4(pVarResult) = msiDoActionStatusUserExit;
1356 break;
1357 case ERROR_INSTALL_FAILURE:
1358 V_I4(pVarResult) = msiDoActionStatusFailure;
1359 break;
1360 case ERROR_INSTALL_SUSPEND:
1361 V_I4(pVarResult) = msiDoActionStatusSuspend;
1362 break;
1363 case ERROR_MORE_DATA:
1364 V_I4(pVarResult) = msiDoActionStatusFinished;
1365 break;
1366 case ERROR_INVALID_HANDLE_STATE:
1367 V_I4(pVarResult) = msiDoActionStatusWrongState;
1368 break;
1369 case ERROR_INVALID_DATA:
1370 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1371 break;
1372 default:
1373 VariantClear(&varg0);
1374 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1375 return DISP_E_EXCEPTION;
1376 }
1377 }
1378 else return DISP_E_MEMBERNOTFOUND;
1379 break;
1380
1381 case DISPID_SESSION_EVALUATECONDITION:
1382 if (wFlags & DISPATCH_METHOD) {
1383 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1384 if (FAILED(hr)) return hr;
1385 V_VT(pVarResult) = VT_I4;
1386 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1387 }
1388 else return DISP_E_MEMBERNOTFOUND;
1389 break;
1390
1391 case DISPID_SESSION_MESSAGE:
1392 if(!(wFlags & DISPATCH_METHOD))
1393 return DISP_E_MEMBERNOTFOUND;
1394
1395 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1396 if (FAILED(hr)) return hr;
1397 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1398 if (FAILED(hr)) return hr;
1399
1400 V_VT(pVarResult) = VT_I4;
1401 V_I4(pVarResult) =
1402 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
1403 break;
1404
1405 case DISPID_SESSION_SETINSTALLLEVEL:
1406 if (wFlags & DISPATCH_METHOD) {
1407 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1408 if (FAILED(hr)) return hr;
1409 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1410 {
1411 ERR("MsiSetInstallLevel returned %d\n", ret);
1412 return DISP_E_EXCEPTION;
1413 }
1414 }
1415 else return DISP_E_MEMBERNOTFOUND;
1416 break;
1417
1418 case DISPID_SESSION_FEATURECURRENTSTATE:
1419 if (wFlags & DISPATCH_PROPERTYGET) {
1420 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1421 if (FAILED(hr)) return hr;
1422 V_VT(pVarResult) = VT_I4;
1423 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1424 V_I4(pVarResult) = iInstalled;
1425 else
1426 {
1427 ERR("MsiGetFeatureState returned %d\n", ret);
1428 V_I4(pVarResult) = msiInstallStateUnknown;
1429 }
1430 }
1431 else return DISP_E_MEMBERNOTFOUND;
1432 break;
1433
1434 case DISPID_SESSION_FEATUREREQUESTSTATE:
1435 if (wFlags & DISPATCH_PROPERTYGET) {
1436 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1437 if (FAILED(hr)) return hr;
1438 V_VT(pVarResult) = VT_I4;
1439 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1440 V_I4(pVarResult) = iAction;
1441 else
1442 {
1443 ERR("MsiGetFeatureState returned %d\n", ret);
1444 V_I4(pVarResult) = msiInstallStateUnknown;
1445 }
1446 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1447 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1448 if (FAILED(hr)) return hr;
1449 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1450 if (FAILED(hr)) {
1451 VariantClear(&varg0);
1452 return hr;
1453 }
1454 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1455 {
1456 VariantClear(&varg0);
1457 ERR("MsiSetFeatureState returned %d\n", ret);
1458 return DISP_E_EXCEPTION;
1459 }
1460 }
1461 else return DISP_E_MEMBERNOTFOUND;
1462 break;
1463
1464 default:
1465 return DISP_E_MEMBERNOTFOUND;
1466 }
1467
1468 VariantClear(&varg1);
1469 VariantClear(&varg0);
1470
1471 return S_OK;
1472 }
1473
1474 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1475 * registry value type. Used by Installer::RegistryValue. */
1476 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1477 {
1478 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1479 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1480 WCHAR *szString = (WCHAR *)lpData;
1481 LPWSTR szNewString = NULL;
1482 DWORD dwNewSize = 0;
1483 int idx;
1484
1485 switch (dwType)
1486 {
1487 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1488 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1489 idx = (dwSize/sizeof(WCHAR))-1;
1490 while (idx >= 0 && !szString[idx]) idx--;
1491 for (; idx >= 0; idx--)
1492 if (!szString[idx]) szString[idx] = '\n';
1493 case REG_SZ:
1494 V_VT(pVarResult) = VT_BSTR;
1495 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1496 break;
1497
1498 case REG_EXPAND_SZ:
1499 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1500 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1501 else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1502 ERR("Out of memory\n");
1503 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1504 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1505 else
1506 {
1507 V_VT(pVarResult) = VT_BSTR;
1508 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1509 }
1510 msi_free(szNewString);
1511 break;
1512
1513 case REG_DWORD:
1514 V_VT(pVarResult) = VT_I4;
1515 V_I4(pVarResult) = *((DWORD *)lpData);
1516 break;
1517
1518 case REG_QWORD:
1519 V_VT(pVarResult) = VT_BSTR;
1520 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1521 break;
1522
1523 case REG_BINARY:
1524 V_VT(pVarResult) = VT_BSTR;
1525 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1526 break;
1527
1528 case REG_NONE:
1529 V_VT(pVarResult) = VT_EMPTY;
1530 break;
1531
1532 default:
1533 FIXME("Unhandled registry value type %d\n", dwType);
1534 }
1535 }
1536
1537 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1538 DISPPARAMS* pDispParams,
1539 VARIANT* pVarResult,
1540 EXCEPINFO* pExcepInfo,
1541 UINT* puArgErr)
1542 {
1543 HRESULT hr;
1544 VARIANTARG varg0;
1545 MSIHANDLE hrec;
1546 IDispatch* dispatch;
1547
1548 if (!(wFlags & DISPATCH_METHOD))
1549 return DISP_E_MEMBERNOTFOUND;
1550
1551 VariantInit(&varg0);
1552 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1553 if (FAILED(hr))
1554 return hr;
1555
1556 V_VT(pVarResult) = VT_DISPATCH;
1557
1558 hrec = MsiCreateRecord(V_I4(&varg0));
1559 if (!hrec)
1560 return DISP_E_EXCEPTION;
1561
1562 hr = create_automation_object(hrec, NULL, (LPVOID*)&dispatch,
1563 &DIID_Record, RecordImpl_Invoke, NULL, 0);
1564 if (SUCCEEDED(hr))
1565 V_DISPATCH(pVarResult) = dispatch;
1566
1567 return hr;
1568 }
1569
1570 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1571 WORD wFlags,
1572 DISPPARAMS* pDispParams,
1573 VARIANT* pVarResult,
1574 EXCEPINFO* pExcepInfo,
1575 UINT* puArgErr)
1576 {
1577 UINT ret;
1578 HRESULT hr;
1579 MSIHANDLE hpkg;
1580 IDispatch* dispatch;
1581 VARIANTARG varg0, varg1;
1582
1583 if (!(wFlags & DISPATCH_METHOD))
1584 return DISP_E_MEMBERNOTFOUND;
1585
1586 if (pDispParams->cArgs == 0)
1587 return DISP_E_TYPEMISMATCH;
1588
1589 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1590 return DISP_E_TYPEMISMATCH;
1591
1592 VariantInit(&varg0);
1593 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1594 if (FAILED(hr))
1595 return hr;
1596
1597 VariantInit(&varg1);
1598 if (pDispParams->cArgs == 2)
1599 {
1600 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1601 if (FAILED(hr))
1602 goto done;
1603 }
1604 else
1605 {
1606 V_VT(&varg1) = VT_I4;
1607 V_I4(&varg1) = 0;
1608 }
1609
1610 V_VT(pVarResult) = VT_DISPATCH;
1611
1612 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1613 if (ret != ERROR_SUCCESS)
1614 {
1615 hr = DISP_E_EXCEPTION;
1616 goto done;
1617 }
1618
1619 hr = create_session(hpkg, (IDispatch *)This, &dispatch);
1620 if (SUCCEEDED(hr))
1621 V_DISPATCH(pVarResult) = dispatch;
1622
1623 done:
1624 VariantClear(&varg0);
1625 VariantClear(&varg1);
1626 return hr;
1627 }
1628
1629 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1630 DISPPARAMS* pDispParams,
1631 VARIANT* pVarResult,
1632 EXCEPINFO* pExcepInfo,
1633 UINT* puArgErr)
1634 {
1635 HRESULT hr;
1636 VARIANTARG varg0;
1637
1638 if (!(wFlags & DISPATCH_METHOD))
1639 return DISP_E_MEMBERNOTFOUND;
1640
1641 VariantInit(&varg0);
1642 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1643 if (FAILED(hr))
1644 return hr;
1645
1646 FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1647
1648 VariantInit(pVarResult);
1649
1650 VariantClear(&varg0);
1651 return S_OK;
1652 }
1653
1654 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1655 DISPPARAMS* pDispParams,
1656 VARIANT* pVarResult,
1657 EXCEPINFO* pExcepInfo,
1658 UINT* puArgErr)
1659 {
1660 UINT ret;
1661 HRESULT hr;
1662 MSIHANDLE hdb;
1663 IDispatch* dispatch;
1664 VARIANTARG varg0, varg1;
1665
1666 if (!(wFlags & DISPATCH_METHOD))
1667 return DISP_E_MEMBERNOTFOUND;
1668
1669 VariantInit(&varg0);
1670 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1671 if (FAILED(hr))
1672 return hr;
1673
1674 VariantInit(&varg1);
1675 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1676 if (FAILED(hr))
1677 goto done;
1678
1679 V_VT(pVarResult) = VT_DISPATCH;
1680
1681 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1682 if (ret != ERROR_SUCCESS)
1683 {
1684 hr = DISP_E_EXCEPTION;
1685 goto done;
1686 }
1687
1688 hr = create_automation_object(hdb, NULL, (LPVOID *)&dispatch,
1689 &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1690 if (SUCCEEDED(hr))
1691 V_DISPATCH(pVarResult) = dispatch;
1692
1693 done:
1694 VariantClear(&varg0);
1695 VariantClear(&varg1);
1696 return hr;
1697 }
1698
1699 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1700 DISPPARAMS* pDispParams,
1701 VARIANT* pVarResult,
1702 EXCEPINFO* pExcepInfo,
1703 UINT* puArgErr)
1704 {
1705 if (!(wFlags & DISPATCH_METHOD))
1706 return DISP_E_MEMBERNOTFOUND;
1707
1708 FIXME("\n");
1709
1710 VariantInit(pVarResult);
1711 return S_OK;
1712 }
1713
1714 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1715 DISPPARAMS* pDispParams,
1716 VARIANT* pVarResult,
1717 EXCEPINFO* pExcepInfo,
1718 UINT* puArgErr)
1719 {
1720 HRESULT hr;
1721 VARIANTARG varg0;
1722 INSTALLUILEVEL ui;
1723
1724 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1725 return DISP_E_MEMBERNOTFOUND;
1726
1727 if (wFlags & DISPATCH_PROPERTYPUT)
1728 {
1729 VariantInit(&varg0);
1730 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1731 if (FAILED(hr))
1732 return hr;
1733
1734 ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1735 if (ui == INSTALLUILEVEL_NOCHANGE)
1736 return DISP_E_EXCEPTION;
1737 }
1738 else if (wFlags & DISPATCH_PROPERTYGET)
1739 {
1740 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1741 if (ui == INSTALLUILEVEL_NOCHANGE)
1742 return DISP_E_EXCEPTION;
1743
1744 V_VT(pVarResult) = VT_I4;
1745 V_I4(pVarResult) = ui;
1746 }
1747
1748 return S_OK;
1749 }
1750
1751 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1752 DISPPARAMS* pDispParams,
1753 VARIANT* pVarResult,
1754 EXCEPINFO* pExcepInfo,
1755 UINT* puArgErr)
1756 {
1757 if (!(wFlags & DISPATCH_METHOD))
1758 return DISP_E_MEMBERNOTFOUND;
1759
1760 FIXME("\n");
1761
1762 VariantInit(pVarResult);
1763 return S_OK;
1764 }
1765
1766 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1767 DISPPARAMS* pDispParams,
1768 VARIANT* pVarResult,
1769 EXCEPINFO* pExcepInfo,
1770 UINT* puArgErr)
1771 {
1772 UINT ret;
1773 HRESULT hr;
1774 VARIANTARG varg0, varg1;
1775
1776 if (!(wFlags & DISPATCH_METHOD))
1777 return DISP_E_MEMBERNOTFOUND;
1778
1779 VariantInit(&varg0);
1780 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1781 if (FAILED(hr))
1782 return hr;
1783
1784 VariantInit(&varg1);
1785 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1786 if (FAILED(hr))
1787 goto done;
1788
1789 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1790 if (ret != ERROR_SUCCESS)
1791 {
1792 hr = DISP_E_EXCEPTION;
1793 goto done;
1794 }
1795
1796 done:
1797 VariantClear(&varg0);
1798 VariantClear(&varg1);
1799 return hr;
1800 }
1801
1802 static HRESULT InstallerImpl_Version(WORD wFlags,
1803 VARIANT* pVarResult,
1804 EXCEPINFO* pExcepInfo,
1805 UINT* puArgErr)
1806 {
1807 HRESULT hr;
1808 DLLVERSIONINFO verinfo;
1809 WCHAR version[MAX_PATH];
1810
1811 static const WCHAR format[] = {
1812 '%','d','.','%','d','.','%','d','.','%','d',0};
1813
1814 if (!(wFlags & DISPATCH_PROPERTYGET))
1815 return DISP_E_MEMBERNOTFOUND;
1816
1817 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1818 hr = DllGetVersion(&verinfo);
1819 if (FAILED(hr))
1820 return hr;
1821
1822 sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1823 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1824
1825 V_VT(pVarResult) = VT_BSTR;
1826 V_BSTR(pVarResult) = SysAllocString(version);
1827 return S_OK;
1828 }
1829
1830 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1831 DISPPARAMS* pDispParams,
1832 VARIANT* pVarResult,
1833 EXCEPINFO* pExcepInfo,
1834 UINT* puArgErr)
1835 {
1836 if (!(wFlags & DISPATCH_METHOD))
1837 return DISP_E_MEMBERNOTFOUND;
1838
1839 FIXME("\n");
1840
1841 VariantInit(pVarResult);
1842 return S_OK;
1843 }
1844
1845 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1846 DISPPARAMS* pDispParams,
1847 VARIANT* pVarResult,
1848 EXCEPINFO* pExcepInfo,
1849 UINT* puArgErr)
1850 {
1851 UINT ret;
1852 HKEY hkey = NULL;
1853 HRESULT hr;
1854 UINT posValue;
1855 DWORD type, size;
1856 LPWSTR szString = NULL;
1857 VARIANTARG varg0, varg1, varg2;
1858
1859 if (!(wFlags & DISPATCH_METHOD))
1860 return DISP_E_MEMBERNOTFOUND;
1861
1862 VariantInit(&varg0);
1863 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1864 if (FAILED(hr))
1865 return hr;
1866
1867 VariantInit(&varg1);
1868 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1869 if (FAILED(hr))
1870 goto done;
1871
1872 /* Save valuePos so we can save puArgErr if we are unable to do our type
1873 * conversions.
1874 */
1875 posValue = 2;
1876 VariantInit(&varg2);
1877 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1878 if (FAILED(hr))
1879 goto done;
1880
1881 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
1882 V_I4(&varg0) <= REG_INDEX_DYN_DATA)
1883 {
1884 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
1885 }
1886
1887 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1888
1889 /* Only VT_EMPTY case can do anything if the key doesn't exist. */
1890 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
1891 {
1892 hr = DISP_E_BADINDEX;
1893 goto done;
1894 }
1895
1896 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1897 switch (V_VT(&varg2))
1898 {
1899 /* Return VT_BOOL clarifying whether registry key exists or not. */
1900 case VT_EMPTY:
1901 V_VT(pVarResult) = VT_BOOL;
1902 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1903 break;
1904
1905 /* Return the value of specified key if it exists. */
1906 case VT_BSTR:
1907 ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
1908 NULL, NULL, NULL, &size);
1909 if (ret != ERROR_SUCCESS)
1910 {
1911 hr = DISP_E_BADINDEX;
1912 goto done;
1913 }
1914
1915 szString = msi_alloc(size);
1916 if (!szString)
1917 {
1918 hr = E_OUTOFMEMORY;
1919 goto done;
1920 }
1921
1922 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
1923 &type, (LPBYTE)szString, &size);
1924 if (ret != ERROR_SUCCESS)
1925 {
1926 msi_free(szString);
1927 hr = DISP_E_BADINDEX;
1928 goto done;
1929 }
1930
1931 variant_from_registry_value(pVarResult, type,
1932 (LPBYTE)szString, size);
1933 msi_free(szString);
1934 break;
1935
1936 /* Try to make it into VT_I4, can use VariantChangeType for this. */
1937 default:
1938 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1939 if (FAILED(hr))
1940 {
1941 if (hr == DISP_E_TYPEMISMATCH)
1942 *puArgErr = posValue;
1943
1944 goto done;
1945 }
1946
1947 /* Retrieve class name or maximum value name or subkey name size. */
1948 if (!V_I4(&varg2))
1949 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
1950 NULL, NULL, NULL, NULL, NULL, NULL);
1951 else if (V_I4(&varg2) > 0)
1952 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
1953 NULL, NULL, &size, NULL, NULL, NULL);
1954 else /* V_I4(&varg2) < 0 */
1955 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
1956 NULL, NULL, NULL, NULL, NULL, NULL);
1957
1958 if (ret != ERROR_SUCCESS)
1959 goto done;
1960
1961 szString = msi_alloc(++size * sizeof(WCHAR));
1962 if (!szString)
1963 {
1964 hr = E_OUTOFMEMORY;
1965 goto done;
1966 }
1967
1968 if (!V_I4(&varg2))
1969 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
1970 NULL, NULL, NULL, NULL, NULL, NULL);
1971 else if (V_I4(&varg2) > 0)
1972 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
1973 &size, 0, 0, NULL, NULL);
1974 else /* V_I4(&varg2) < 0 */
1975 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
1976
1977 if (ret == ERROR_SUCCESS)
1978 {
1979 V_VT(pVarResult) = VT_BSTR;
1980 V_BSTR(pVarResult) = SysAllocString(szString);
1981 }
1982
1983 msi_free(szString);
1984 }
1985
1986 done:
1987 VariantClear(&varg0);
1988 VariantClear(&varg1);
1989 VariantClear(&varg2);
1990 RegCloseKey(hkey);
1991 return hr;
1992 }
1993
1994 static HRESULT InstallerImpl_Environment(WORD wFlags,
1995 DISPPARAMS* pDispParams,
1996 VARIANT* pVarResult,
1997 EXCEPINFO* pExcepInfo,
1998 UINT* puArgErr)
1999 {
2000 if (!(wFlags & DISPATCH_METHOD))
2001 return DISP_E_MEMBERNOTFOUND;
2002
2003 FIXME("\n");
2004
2005 VariantInit(pVarResult);
2006 return S_OK;
2007 }
2008
2009 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2010 DISPPARAMS* pDispParams,
2011 VARIANT* pVarResult,
2012 EXCEPINFO* pExcepInfo,
2013 UINT* puArgErr)
2014 {
2015 if (!(wFlags & DISPATCH_METHOD))
2016 return DISP_E_MEMBERNOTFOUND;
2017
2018 FIXME("\n");
2019
2020 VariantInit(pVarResult);
2021 return S_OK;
2022 }
2023
2024 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2025 DISPPARAMS* pDispParams,
2026 VARIANT* pVarResult,
2027 EXCEPINFO* pExcepInfo,
2028 UINT* puArgErr)
2029 {
2030 if (!(wFlags & DISPATCH_METHOD))
2031 return DISP_E_MEMBERNOTFOUND;
2032
2033 FIXME("\n");
2034
2035 VariantInit(pVarResult);
2036 return S_OK;
2037 }
2038
2039 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2040 DISPPARAMS* pDispParams,
2041 VARIANT* pVarResult,
2042 EXCEPINFO* pExcepInfo,
2043 UINT* puArgErr)
2044 {
2045 if (!(wFlags & DISPATCH_METHOD))
2046 return DISP_E_MEMBERNOTFOUND;
2047
2048 FIXME("\n");
2049
2050 VariantInit(pVarResult);
2051 return S_OK;
2052 }
2053
2054 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2055 DISPPARAMS* pDispParams,
2056 VARIANT* pVarResult,
2057 EXCEPINFO* pExcepInfo,
2058 UINT* puArgErr)
2059 {
2060 HRESULT hr;
2061 VARIANTARG varg0;
2062
2063 if (!(wFlags & DISPATCH_PROPERTYGET))
2064 return DISP_E_MEMBERNOTFOUND;
2065
2066 VariantInit(&varg0);
2067 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2068 if (FAILED(hr))
2069 return hr;
2070
2071 V_VT(pVarResult) = VT_I4;
2072 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2073
2074 VariantClear(&varg0);
2075 return S_OK;
2076 }
2077
2078 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2079 DISPPARAMS* pDispParams,
2080 VARIANT* pVarResult,
2081 EXCEPINFO* pExcepInfo,
2082 UINT* puArgErr)
2083 {
2084 UINT ret;
2085 HRESULT hr;
2086 DWORD size;
2087 LPWSTR str = NULL;
2088 VARIANTARG varg0, varg1;
2089
2090 if (!(wFlags & DISPATCH_PROPERTYGET))
2091 return DISP_E_MEMBERNOTFOUND;
2092
2093 VariantInit(&varg0);
2094 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2095 if (FAILED(hr))
2096 return hr;
2097
2098 VariantInit(&varg1);
2099 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2100 if (FAILED(hr))
2101 goto done;
2102
2103 V_VT(pVarResult) = VT_BSTR;
2104 V_BSTR(pVarResult) = NULL;
2105
2106 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2107 if (ret != ERROR_SUCCESS)
2108 {
2109 hr = DISP_E_EXCEPTION;
2110 goto done;
2111 }
2112
2113 str = msi_alloc(++size * sizeof(WCHAR));
2114 if (!str)
2115 {
2116 hr = E_OUTOFMEMORY;
2117 goto done;
2118 }
2119
2120 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2121 if (ret != ERROR_SUCCESS)
2122 {
2123 hr = DISP_E_EXCEPTION;
2124 goto done;
2125 }
2126
2127 V_BSTR(pVarResult) = SysAllocString(str);
2128 hr = S_OK;
2129
2130 done:
2131 msi_free(str);
2132 VariantClear(&varg0);
2133 VariantClear(&varg1);
2134 return hr;
2135 }
2136
2137 static void cleanup_products(IDispatch* dispatch, ULONG count)
2138 {
2139 UINT i;
2140 ListData* ldata = private_data((AutomationObject *)dispatch);
2141
2142 for (i = 0; i < count - 1; i++)
2143 VariantClear(&ldata->pVars[i]);
2144
2145 ldata->ulCount = 0;
2146 msi_free(ldata->pVars);
2147
2148 IDispatch_Release(dispatch);
2149 }
2150
2151 static HRESULT InstallerImpl_Products(WORD wFlags,
2152 DISPPARAMS* pDispParams,
2153 VARIANT* pVarResult,
2154 EXCEPINFO* pExcepInfo,
2155 UINT* puArgErr)
2156 {
2157 UINT ret;
2158 HRESULT hr;
2159 ULONG idx = 0;
2160 ListData *ldata;
2161 IDispatch *dispatch;
2162 WCHAR product[GUID_SIZE];
2163
2164 if (!(wFlags & DISPATCH_PROPERTYGET))
2165 return DISP_E_MEMBERNOTFOUND;
2166
2167 /* Find number of products. */
2168 while ((ret = MsiEnumProductsW(idx, product)) == ERROR_SUCCESS)
2169 idx++;
2170
2171 if (ret != ERROR_NO_MORE_ITEMS)
2172 return DISP_E_EXCEPTION;
2173
2174 V_VT(pVarResult) = VT_DISPATCH;
2175 hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2176 &DIID_StringList, ListImpl_Invoke,
2177 ListImpl_Free, sizeof(ListData));
2178 if (FAILED(hr))
2179 return hr;
2180
2181 V_DISPATCH(pVarResult) = dispatch;
2182
2183 /* Save product strings. */
2184 ldata = private_data((AutomationObject *)dispatch);
2185 ldata->ulCount = 0;
2186 ldata->pVars = msi_alloc_zero(sizeof(VARIANT) * idx);
2187 if (!ldata->pVars)
2188 {
2189 IDispatch_Release(dispatch);
2190 return E_OUTOFMEMORY;
2191 }
2192
2193 ldata->ulCount = idx;
2194 for (idx = 0; idx < ldata->ulCount; idx++)
2195 {
2196 ret = MsiEnumProductsW(idx, product);
2197 if (ret != ERROR_SUCCESS)
2198 {
2199 cleanup_products(dispatch, idx - 1);
2200 return DISP_E_EXCEPTION;
2201 }
2202
2203 VariantInit(&ldata->pVars[idx]);
2204 V_VT(&ldata->pVars[idx]) = VT_BSTR;
2205 V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2206 }
2207
2208 return S_OK;
2209 }
2210
2211 static HRESULT InstallerImpl_RelatedProducts(WORD wFlags,
2212 DISPPARAMS* pDispParams,
2213 VARIANT* pVarResult,
2214 EXCEPINFO* pExcepInfo,
2215 UINT* puArgErr)
2216 {
2217 UINT ret;
2218 ULONG idx;
2219 HRESULT hr;
2220 ListData *ldata;
2221 VARIANTARG varg0;
2222 IDispatch* dispatch;
2223 WCHAR product[GUID_SIZE];
2224
2225 if (!(wFlags & DISPATCH_PROPERTYGET))
2226 return DISP_E_MEMBERNOTFOUND;
2227
2228 VariantInit(&varg0);
2229 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2230 if (FAILED(hr))
2231 return hr;
2232
2233 /* Find number of related products. */
2234 idx = 0;
2235 do
2236 {
2237 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2238 if (ret == ERROR_SUCCESS)
2239 idx++;
2240 } while (ret == ERROR_SUCCESS);
2241
2242 if (ret != ERROR_NO_MORE_ITEMS)
2243 {
2244 hr = DISP_E_EXCEPTION;
2245 goto done;
2246 }
2247
2248 V_VT(pVarResult) = VT_DISPATCH;
2249
2250 hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2251 &DIID_StringList, ListImpl_Invoke,
2252 ListImpl_Free, sizeof(ListData));
2253 if (FAILED(hr))
2254 goto done;
2255
2256 V_DISPATCH(pVarResult) = dispatch;
2257
2258 /* Save product strings. */
2259 ldata = private_data((AutomationObject *)dispatch);
2260 ldata->pVars = msi_alloc(sizeof(VARIANT) * idx);
2261 if (!ldata->pVars)
2262 {
2263 IDispatch_Release(dispatch);
2264 hr = E_OUTOFMEMORY;
2265 goto done;
2266 }
2267
2268 ldata->ulCount = idx;
2269 for (idx = 0; idx < ldata->ulCount; idx++)
2270 {
2271 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2272 if (ret != ERROR_SUCCESS)
2273 {
2274 cleanup_products(dispatch, idx - 1);
2275 hr = DISP_E_EXCEPTION;
2276 goto done;
2277 }
2278
2279 VariantInit(&ldata->pVars[idx]);
2280 V_VT(&ldata->pVars[idx]) = VT_BSTR;
2281 V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2282 }
2283
2284 hr = S_OK;
2285
2286 done:
2287 VariantClear(&varg0);
2288 return hr;
2289 }
2290
2291 static HRESULT WINAPI InstallerImpl_Invoke(
2292 AutomationObject* This,
2293 DISPID dispIdMember,
2294 REFIID riid,
2295 LCID lcid,
2296 WORD wFlags,
2297 DISPPARAMS* pDispParams,
2298 VARIANT* pVarResult,
2299 EXCEPINFO* pExcepInfo,
2300 UINT* puArgErr)
2301 {
2302 switch (dispIdMember)
2303 {
2304 case DISPID_INSTALLER_CREATERECORD:
2305 return InstallerImpl_CreateRecord(wFlags, pDispParams,
2306 pVarResult, pExcepInfo, puArgErr);
2307
2308 case DISPID_INSTALLER_OPENPACKAGE:
2309 return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2310 pVarResult, pExcepInfo, puArgErr);
2311
2312 case DISPID_INSTALLER_OPENPRODUCT:
2313 return InstallerImpl_OpenProduct(wFlags, pDispParams,
2314 pVarResult, pExcepInfo, puArgErr);
2315
2316 case DISPID_INSTALLER_OPENDATABASE:
2317 return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2318 pVarResult, pExcepInfo, puArgErr);
2319
2320 case DISPID_INSTALLER_SUMMARYINFORMATION:
2321 return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2322 pVarResult, pExcepInfo,
2323 puArgErr);
2324
2325 case DISPID_INSTALLER_UILEVEL:
2326 return InstallerImpl_UILevel(wFlags, pDispParams,
2327 pVarResult, pExcepInfo, puArgErr);
2328
2329 case DISPID_INSTALLER_ENABLELOG:
2330 return InstallerImpl_EnableLog(wFlags, pDispParams,
2331 pVarResult, pExcepInfo, puArgErr);
2332
2333 case DISPID_INSTALLER_INSTALLPRODUCT:
2334 return InstallerImpl_InstallProduct(wFlags, pDispParams,
2335 pVarResult, pExcepInfo,
2336 puArgErr);
2337
2338 case DISPID_INSTALLER_VERSION:
2339 return InstallerImpl_Version(wFlags, pVarResult,
2340 pExcepInfo, puArgErr);
2341
2342 case DISPID_INSTALLER_LASTERRORRECORD:
2343 return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2344 pVarResult, pExcepInfo,
2345 puArgErr);
2346
2347 case DISPID_INSTALLER_REGISTRYVALUE:
2348 return InstallerImpl_RegistryValue(wFlags, pDispParams,
2349 pVarResult, pExcepInfo,
2350 puArgErr);
2351
2352 case DISPID_INSTALLER_ENVIRONMENT:
2353 return InstallerImpl_Environment(wFlags, pDispParams,
2354 pVarResult, pExcepInfo, puArgErr);
2355
2356 case DISPID_INSTALLER_FILEATTRIBUTES:
2357 return InstallerImpl_FileAttributes(wFlags, pDispParams,
2358 pVarResult, pExcepInfo,
2359 puArgErr);
2360
2361 case DISPID_INSTALLER_FILESIZE:
2362 return InstallerImpl_FileSize(wFlags, pDispParams,
2363 pVarResult, pExcepInfo, puArgErr);
2364
2365 case DISPID_INSTALLER_FILEVERSION:
2366 return InstallerImpl_FileVersion(wFlags, pDispParams,
2367 pVarResult, pExcepInfo, puArgErr);
2368
2369 case DISPID_INSTALLER_PRODUCTSTATE:
2370 return InstallerImpl_ProductState(wFlags, pDispParams,
2371 pVarResult, pExcepInfo, puArgErr);
2372
2373 case DISPID_INSTALLER_PRODUCTINFO:
2374 return InstallerImpl_ProductInfo(wFlags, pDispParams,
2375 pVarResult, pExcepInfo, puArgErr);
2376
2377 case DISPID_INSTALLER_PRODUCTS:
2378 return InstallerImpl_Products(wFlags, pDispParams,
2379 pVarResult, pExcepInfo, puArgErr);
2380
2381 case DISPID_INSTALLER_RELATEDPRODUCTS:
2382 return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2383 pVarResult, pExcepInfo,
2384 puArgErr);
2385
2386 default:
2387 return DISP_E_MEMBERNOTFOUND;
2388 }
2389 }
2390
2391 /* Wrapper around create_automation_object to create an installer object. */
2392 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
2393 {
2394 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
2395 }
2396
2397 /* Wrapper around create_automation_object to create a session object. */
2398 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
2399 {
2400 HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
2401 if (SUCCEEDED(hr) && pDispatch && *pDispatch)
2402 ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
2403 return hr;
2404 }