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