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