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