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