ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

automation.c
Go to the documentation of this file.
00001 /*
00002  * Implementation of OLE Automation for Microsoft Installer (msi.dll)
00003  *
00004  * Copyright 2007 Misha Koshelev
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  */
00020 
00021 #define COBJMACROS
00022 
00023 #include <stdarg.h>
00024 #include "windef.h"
00025 #include "winbase.h"
00026 #include "winerror.h"
00027 #include "winuser.h"
00028 #include "winreg.h"
00029 #include "msidefs.h"
00030 #include "msipriv.h"
00031 #include "activscp.h"
00032 #include "oleauto.h"
00033 #include "shlwapi.h"
00034 #include "wine/debug.h"
00035 #include "wine/unicode.h"
00036 
00037 #include "msiserver.h"
00038 #include "msiserver_dispids.h"
00039 
00040 WINE_DEFAULT_DEBUG_CHANNEL(msi);
00041 
00042 #define REG_INDEX_CLASSES_ROOT 0
00043 #define REG_INDEX_DYN_DATA 6
00044 
00045 /*
00046  * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
00047  *                    called from AutomationObject::Invoke.
00048  */
00049 
00050 typedef struct AutomationObject AutomationObject;
00051 
00052 typedef HRESULT (*autoInvokeFunc)(AutomationObject* This,
00053     DISPID dispIdMember, REFIID riid, LCID lcid, WORD flags, DISPPARAMS* pDispParams,
00054     VARIANT* result, EXCEPINFO* ei, UINT* arg_err);
00055 
00056 typedef void (*autoFreeFunc)(AutomationObject* This);
00057 
00058 struct AutomationObject {
00059     IDispatch IDispatch_iface;
00060     IProvideMultipleClassInfo IProvideMultipleClassInfo_iface;
00061     LONG ref;
00062 
00063     /* Clsid for this class and it's appropriate ITypeInfo object */
00064     LPCLSID clsid;
00065     ITypeInfo *iTypeInfo;
00066 
00067     /* The MSI handle of the current object */
00068     MSIHANDLE msiHandle;
00069 
00070     /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
00071     autoInvokeFunc funcInvoke;
00072     /* A function that is called from AutomationObject::Release when the object is being freed to free any private
00073      * data structures (or NULL) */
00074     autoFreeFunc funcFree;
00075 };
00076 
00077 typedef struct {
00078     AutomationObject autoobj;
00079     int count;
00080     VARIANT *data;
00081 } ListObject;
00082 
00083 static HRESULT create_database(MSIHANDLE, IDispatch**);
00084 static HRESULT create_list_enumerator(ListObject*, void**);
00085 static HRESULT create_summaryinfo(MSIHANDLE, IDispatch**);
00086 static HRESULT create_view(MSIHANDLE, IDispatch**);
00087 
00088 /* ListEnumerator - IEnumVARIANT implementation for MSI automation lists */
00089 typedef struct {
00090     IEnumVARIANT IEnumVARIANT_iface;
00091     LONG ref;
00092 
00093     /* Current position and pointer to AutomationObject that stores actual data */
00094     ULONG pos;
00095     ListObject *list;
00096 } ListEnumerator;
00097 
00098 typedef struct {
00099     AutomationObject autoobj;
00100     IDispatch *installer;
00101 } SessionObject;
00102 
00103 static inline AutomationObject *impl_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
00104 {
00105     return CONTAINING_RECORD(iface, AutomationObject, IProvideMultipleClassInfo_iface);
00106 }
00107 
00108 static inline AutomationObject *impl_from_IDispatch( IDispatch *iface )
00109 {
00110     return CONTAINING_RECORD(iface, AutomationObject, IDispatch_iface);
00111 }
00112 
00113 /* Load type info so we don't have to process GetIDsOfNames */
00114 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
00115 {
00116     static const WCHAR msiserverW[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b',0};
00117     ITypeInfo *ti = NULL;
00118     ITypeLib *lib = NULL;
00119     HRESULT hr;
00120 
00121     TRACE("(%p)->(%s, %d)\n", iface, debugstr_guid(clsid), lcid);
00122 
00123     /* Load registered type library */
00124     hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &lib);
00125     if (FAILED(hr)) {
00126         hr = LoadTypeLib(msiserverW, &lib);
00127         if (FAILED(hr)) {
00128             ERR("Could not load msiserver.tlb\n");
00129             return hr;
00130         }
00131     }
00132 
00133     /* Get type information for object */
00134     hr = ITypeLib_GetTypeInfoOfGuid(lib, clsid, &ti);
00135     ITypeLib_Release(lib);
00136     if (FAILED(hr)) {
00137         ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
00138         return hr;
00139     }
00140     *pptinfo = ti;
00141     return S_OK;
00142 }
00143 
00144 /* AutomationObject methods */
00145 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
00146 {
00147     AutomationObject *This = impl_from_IDispatch(iface);
00148 
00149     TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
00150 
00151     if (ppvObject == NULL)
00152       return E_INVALIDARG;
00153 
00154     *ppvObject = 0;
00155 
00156     if (IsEqualGUID(riid, &IID_IUnknown)  ||
00157         IsEqualGUID(riid, &IID_IDispatch) ||
00158         IsEqualGUID(riid, This->clsid))
00159         *ppvObject = &This->IDispatch_iface;
00160     else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
00161              IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
00162              IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
00163         *ppvObject = &This->IProvideMultipleClassInfo_iface;
00164     else
00165     {
00166         TRACE("() : asking for unsupported interface %s\n", debugstr_guid(riid));
00167         return E_NOINTERFACE;
00168     }
00169 
00170     IDispatch_AddRef(iface);
00171 
00172     return S_OK;
00173 }
00174 
00175 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
00176 {
00177     AutomationObject *This = impl_from_IDispatch(iface);
00178 
00179     TRACE("(%p/%p)\n", iface, This);
00180 
00181     return InterlockedIncrement(&This->ref);
00182 }
00183 
00184 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
00185 {
00186     AutomationObject *This = impl_from_IDispatch(iface);
00187     ULONG ref = InterlockedDecrement(&This->ref);
00188 
00189     TRACE("(%p/%p)\n", iface, This);
00190 
00191     if (!ref)
00192     {
00193         if (This->funcFree) This->funcFree(This);
00194         ITypeInfo_Release(This->iTypeInfo);
00195         MsiCloseHandle(This->msiHandle);
00196         msi_free(This);
00197     }
00198 
00199     return ref;
00200 }
00201 
00202 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
00203         IDispatch* iface,
00204         UINT* pctinfo)
00205 {
00206     AutomationObject *This = impl_from_IDispatch(iface);
00207 
00208     TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
00209     *pctinfo = 1;
00210     return S_OK;
00211 }
00212 
00213 static HRESULT WINAPI AutomationObject_GetTypeInfo(
00214         IDispatch* iface,
00215         UINT iTInfo,
00216         LCID lcid,
00217         ITypeInfo** ppTInfo)
00218 {
00219     AutomationObject *This = impl_from_IDispatch(iface);
00220     TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
00221 
00222     ITypeInfo_AddRef(This->iTypeInfo);
00223     *ppTInfo = This->iTypeInfo;
00224     return S_OK;
00225 }
00226 
00227 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
00228         IDispatch* iface,
00229         REFIID riid,
00230         LPOLESTR* rgszNames,
00231         UINT cNames,
00232         LCID lcid,
00233         DISPID* rgDispId)
00234 {
00235     AutomationObject *This = impl_from_IDispatch(iface);
00236     HRESULT hr;
00237     TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
00238 
00239     if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
00240     hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
00241     if (hr == DISP_E_UNKNOWNNAME)
00242     {
00243         UINT idx;
00244         for (idx=0; idx<cNames; idx++)
00245         {
00246             if (rgDispId[idx] == DISPID_UNKNOWN)
00247                 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
00248         }
00249     }
00250     return hr;
00251 }
00252 
00253 /* Maximum number of allowed function parameters+1 */
00254 #define MAX_FUNC_PARAMS 20
00255 
00256 /* Some error checking is done here to simplify individual object function invocation */
00257 static HRESULT WINAPI AutomationObject_Invoke(
00258         IDispatch* iface,
00259         DISPID dispIdMember,
00260         REFIID riid,
00261         LCID lcid,
00262         WORD wFlags,
00263         DISPPARAMS* pDispParams,
00264         VARIANT* pVarResult,
00265         EXCEPINFO* pExcepInfo,
00266         UINT* puArgErr)
00267 {
00268     AutomationObject *This = impl_from_IDispatch(iface);
00269     HRESULT hr;
00270     unsigned int uArgErr;
00271     VARIANT varResultDummy;
00272     BSTR bstrName = NULL;
00273 
00274     TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
00275 
00276     if (!IsEqualIID(riid, &IID_NULL))
00277     {
00278         ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
00279         return DISP_E_UNKNOWNNAME;
00280     }
00281 
00282     if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
00283     {
00284         ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
00285         return DISP_E_PARAMNOTOPTIONAL;
00286     }
00287 
00288     /* This simplifies our individual object invocation functions */
00289     if (puArgErr == NULL) puArgErr = &uArgErr;
00290     if (pVarResult == NULL) pVarResult = &varResultDummy;
00291 
00292     /* Assume return type is void unless determined otherwise */
00293     VariantInit(pVarResult);
00294 
00295     /* If we are tracing, we want to see the name of the member we are invoking */
00296     if (TRACE_ON(msi))
00297     {
00298         ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
00299         TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
00300     }
00301 
00302     hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
00303 
00304     if (hr == DISP_E_MEMBERNOTFOUND) {
00305         if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
00306         FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
00307     }
00308     else if (pExcepInfo &&
00309              (hr == DISP_E_PARAMNOTFOUND ||
00310               hr == DISP_E_EXCEPTION)) {
00311         static const WCHAR szComma[] = { ',',0 };
00312         static const WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
00313         WCHAR szExceptionDescription[MAX_PATH];
00314         BSTR bstrParamNames[MAX_FUNC_PARAMS];
00315         unsigned namesNo, i;
00316         BOOL bFirst = TRUE;
00317 
00318         if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
00319                                       MAX_FUNC_PARAMS, &namesNo)))
00320         {
00321             TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
00322         }
00323         else
00324         {
00325             memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
00326             for (i=0; i<namesNo; i++)
00327             {
00328                 if (bFirst) bFirst = FALSE;
00329                 else {
00330                     lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
00331                 }
00332                 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
00333                 SysFreeString(bstrParamNames[i]);
00334             }
00335 
00336             memset(pExcepInfo, 0, sizeof(EXCEPINFO));
00337             pExcepInfo->wCode = 1000;
00338             pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
00339             pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
00340             hr = DISP_E_EXCEPTION;
00341         }
00342     }
00343 
00344     /* Make sure we free the return variant if it is our dummy variant */
00345     if (pVarResult == &varResultDummy) VariantClear(pVarResult);
00346 
00347     /* Free function name if we retrieved it */
00348     SysFreeString(bstrName);
00349 
00350     TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
00351 
00352     return hr;
00353 }
00354 
00355 static const struct IDispatchVtbl AutomationObjectVtbl =
00356 {
00357     AutomationObject_QueryInterface,
00358     AutomationObject_AddRef,
00359     AutomationObject_Release,
00360     AutomationObject_GetTypeInfoCount,
00361     AutomationObject_GetTypeInfo,
00362     AutomationObject_GetIDsOfNames,
00363     AutomationObject_Invoke
00364 };
00365 
00366 /*
00367  * IProvideMultipleClassInfo methods
00368  */
00369 
00370 static HRESULT WINAPI ProvideMultipleClassInfo_QueryInterface(
00371   IProvideMultipleClassInfo* iface,
00372   REFIID     riid,
00373   VOID**     ppvoid)
00374 {
00375     AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
00376     return IDispatch_QueryInterface(&This->IDispatch_iface, riid, ppvoid);
00377 }
00378 
00379 static ULONG WINAPI ProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
00380 {
00381     AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
00382     return IDispatch_AddRef(&This->IDispatch_iface);
00383 }
00384 
00385 static ULONG WINAPI ProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
00386 {
00387     AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
00388     return IDispatch_Release(&This->IDispatch_iface);
00389 }
00390 
00391 static HRESULT WINAPI ProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
00392 {
00393     AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
00394     TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
00395     return load_type_info(&This->IDispatch_iface, ppTI, This->clsid, 0);
00396 }
00397 
00398 static HRESULT WINAPI ProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
00399 {
00400     AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
00401     TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
00402 
00403     if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
00404         return E_INVALIDARG;
00405     else {
00406         *pGUID = *This->clsid;
00407         return S_OK;
00408     }
00409 }
00410 
00411 static HRESULT WINAPI ProvideMultipleClassInfo_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
00412 {
00413     AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
00414 
00415     TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
00416     *pcti = 1;
00417     return S_OK;
00418 }
00419 
00420 static HRESULT WINAPI ProvideMultipleClassInfo_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
00421         ULONG iti,
00422         DWORD dwFlags,
00423         ITypeInfo** pptiCoClass,
00424         DWORD* pdwTIFlags,
00425         ULONG* pcdispidReserved,
00426         IID* piidPrimary,
00427         IID* piidSource)
00428 {
00429     AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
00430 
00431     TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
00432 
00433     if (iti != 0)
00434         return E_INVALIDARG;
00435 
00436     if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
00437         load_type_info(&This->IDispatch_iface, pptiCoClass, This->clsid, 0);
00438 
00439     if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
00440     {
00441         *pdwTIFlags = 0;
00442         *pcdispidReserved = 0;
00443     }
00444 
00445     if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
00446         *piidPrimary = *This->clsid;
00447     }
00448 
00449     if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
00450         *piidSource = *This->clsid;
00451     }
00452 
00453     return S_OK;
00454 }
00455 
00456 static const IProvideMultipleClassInfoVtbl ProvideMultipleClassInfoVtbl =
00457 {
00458     ProvideMultipleClassInfo_QueryInterface,
00459     ProvideMultipleClassInfo_AddRef,
00460     ProvideMultipleClassInfo_Release,
00461     ProvideMultipleClassInfo_GetClassInfo,
00462     ProvideMultipleClassInfo_GetGUID,
00463     ProvideMultipleClassInfo_GetMultiTypeInfoCount,
00464     ProvideMultipleClassInfo_GetInfoOfIndex
00465 };
00466 
00467 static HRESULT init_automation_object(AutomationObject *This, MSIHANDLE msiHandle, REFIID clsid,
00468         autoInvokeFunc invokeFunc, autoFreeFunc freeFunc)
00469 {
00470     TRACE("(%p, %d, %s, %p, %p)\n", This, msiHandle, debugstr_guid(clsid), invokeFunc, freeFunc);
00471 
00472     This->IDispatch_iface.lpVtbl = &AutomationObjectVtbl;
00473     This->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl;
00474     This->ref = 1;
00475 
00476     This->msiHandle = msiHandle;
00477     This->clsid = (LPCLSID)clsid;
00478     This->funcInvoke = invokeFunc;
00479     This->funcFree   = freeFunc;
00480 
00481     /* Load our TypeInfo so we don't have to process GetIDsOfNames */
00482     This->iTypeInfo = NULL;
00483     return load_type_info(&This->IDispatch_iface, &This->iTypeInfo, clsid, 0);
00484 }
00485 
00486 /*
00487  * ListEnumerator methods
00488  */
00489 
00490 static inline ListEnumerator *impl_from_IEnumVARIANT(IEnumVARIANT* iface)
00491 {
00492     return CONTAINING_RECORD(iface, ListEnumerator, IEnumVARIANT_iface);
00493 }
00494 
00495 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid,
00496         void** ppvObject)
00497 {
00498     ListEnumerator *This = impl_from_IEnumVARIANT(iface);
00499 
00500     TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
00501 
00502     if (ppvObject == NULL)
00503       return E_INVALIDARG;
00504 
00505     *ppvObject = 0;
00506 
00507     if (IsEqualGUID(riid, &IID_IUnknown) ||
00508         IsEqualGUID(riid, &IID_IEnumVARIANT))
00509     {
00510         *ppvObject = &This->IEnumVARIANT_iface;
00511     }
00512     else
00513     {
00514         TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
00515         return E_NOINTERFACE;
00516     }
00517 
00518     IEnumVARIANT_AddRef(iface);
00519     return S_OK;
00520 }
00521 
00522 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
00523 {
00524     ListEnumerator *This = impl_from_IEnumVARIANT(iface);
00525 
00526     TRACE("(%p/%p)\n", iface, This);
00527 
00528     return InterlockedIncrement(&This->ref);
00529 }
00530 
00531 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
00532 {
00533     ListEnumerator *This = impl_from_IEnumVARIANT(iface);
00534     ULONG ref = InterlockedDecrement(&This->ref);
00535 
00536     TRACE("(%p/%p)\n", iface, This);
00537 
00538     if (!ref)
00539     {
00540         if (This->list) IDispatch_Release(&This->list->autoobj.IDispatch_iface);
00541         msi_free(This);
00542     }
00543 
00544     return ref;
00545 }
00546 
00547 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar,
00548         ULONG* fetched)
00549 {
00550     ListEnumerator *This = impl_from_IEnumVARIANT(iface);
00551     ULONG i, local;
00552 
00553     TRACE("(%p, %uld, %p, %p)\n", iface, celt, rgVar, fetched);
00554 
00555     if (fetched) *fetched = 0;
00556 
00557     if (!rgVar)
00558         return S_FALSE;
00559 
00560     for (local = 0; local < celt; local++)
00561         VariantInit(&rgVar[local]);
00562 
00563     for (i = This->pos, local = 0; i < This->list->count && local < celt; i++, local++)
00564         VariantCopy(&rgVar[local], &This->list->data[i]);
00565 
00566     if (fetched) *fetched = local;
00567     This->pos = i;
00568 
00569     return (local < celt) ? S_FALSE : S_OK;
00570 }
00571 
00572 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
00573 {
00574     ListEnumerator *This = impl_from_IEnumVARIANT(iface);
00575 
00576     TRACE("(%p,%uld)\n", iface, celt);
00577 
00578     This->pos += celt;
00579     if (This->pos >= This->list->count)
00580     {
00581         This->pos = This->list->count;
00582         return S_FALSE;
00583     }
00584 
00585     return S_OK;
00586 }
00587 
00588 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
00589 {
00590     ListEnumerator *This = impl_from_IEnumVARIANT(iface);
00591 
00592     TRACE("(%p)\n", iface);
00593 
00594     This->pos = 0;
00595     return S_OK;
00596 }
00597 
00598 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
00599 {
00600     ListEnumerator *This = impl_from_IEnumVARIANT(iface);
00601     HRESULT hr;
00602 
00603     TRACE("(%p,%p)\n", iface, ppEnum);
00604 
00605     if (ppEnum == NULL)
00606         return S_FALSE;
00607 
00608     *ppEnum = NULL;
00609     hr = create_list_enumerator(This->list, (LPVOID *)ppEnum);
00610     if (FAILED(hr))
00611     {
00612         if (*ppEnum)
00613             IUnknown_Release(*ppEnum);
00614         return hr;
00615     }
00616 
00617     return S_OK;
00618 }
00619 
00620 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
00621 {
00622     ListEnumerator_QueryInterface,
00623     ListEnumerator_AddRef,
00624     ListEnumerator_Release,
00625     ListEnumerator_Next,
00626     ListEnumerator_Skip,
00627     ListEnumerator_Reset,
00628     ListEnumerator_Clone
00629 };
00630 
00631 /* Create a list enumerator, placing the result in the pointer ppObj.  */
00632 static HRESULT create_list_enumerator(ListObject *list, void **ppObj)
00633 {
00634     ListEnumerator *object;
00635 
00636     TRACE("(%p, %p)\n", list, ppObj);
00637 
00638     object = msi_alloc(sizeof(ListEnumerator));
00639 
00640     /* Set all the VTable references */
00641     object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
00642     object->ref = 1;
00643 
00644     /* Store data that was passed */
00645     object->pos = 0;
00646     object->list = list;
00647     if (list) IDispatch_AddRef(&list->autoobj.IDispatch_iface);
00648 
00649     *ppObj = object;
00650     return S_OK;
00651 }
00652 
00653 /*
00654  * Individual Object Invocation Functions
00655  */
00656 
00657 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
00658    This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
00659    using DispGetParam/VariantChangeType. */
00660 static HRESULT DispGetParam_CopyOnly(
00661         DISPPARAMS *pdispparams, /* [in] Parameter list */
00662         UINT        *position,    /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
00663         VARIANT    *pvarResult)  /* [out] Destination for resulting variant */
00664 {
00665     /* position is counted backwards */
00666     UINT pos;
00667 
00668     TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
00669           *position, pdispparams->cArgs, pdispparams->cNamedArgs);
00670     if (*position < pdispparams->cArgs) {
00671       /* positional arg? */
00672       pos = pdispparams->cArgs - *position - 1;
00673     } else {
00674       /* FIXME: is this how to handle named args? */
00675       for (pos=0; pos<pdispparams->cNamedArgs; pos++)
00676         if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
00677 
00678       if (pos==pdispparams->cNamedArgs)
00679         return DISP_E_PARAMNOTFOUND;
00680     }
00681     *position = pos;
00682     return VariantCopyInd(pvarResult,
00683                         &pdispparams->rgvarg[pos]);
00684 }
00685 
00686 static HRESULT SummaryInfoImpl_Invoke(
00687         AutomationObject* This,
00688         DISPID dispIdMember,
00689         REFIID riid,
00690         LCID lcid,
00691         WORD wFlags,
00692         DISPPARAMS* pDispParams,
00693         VARIANT* pVarResult,
00694         EXCEPINFO* pExcepInfo,
00695         UINT* puArgErr)
00696 {
00697     UINT ret;
00698     VARIANTARG varg0, varg1;
00699     FILETIME ft, ftlocal;
00700     SYSTEMTIME st;
00701     HRESULT hr;
00702 
00703     VariantInit(&varg0);
00704     VariantInit(&varg1);
00705 
00706     switch (dispIdMember)
00707     {
00708         case DISPID_SUMMARYINFO_PROPERTY:
00709             if (wFlags & DISPATCH_PROPERTYGET)
00710             {
00711                 UINT type;
00712                 INT value;
00713                 DWORD size = 0;
00714                 DATE date;
00715                 LPWSTR str;
00716 
00717                 static WCHAR szEmpty[] = {0};
00718 
00719                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
00720                 if (FAILED(hr)) return hr;
00721                 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
00722                                                  &ft, szEmpty, &size);
00723                 if (ret != ERROR_SUCCESS &&
00724                     ret != ERROR_MORE_DATA)
00725                 {
00726                     ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
00727                     return DISP_E_EXCEPTION;
00728                 }
00729 
00730                 switch (type)
00731                 {
00732                     case VT_EMPTY:
00733                         break;
00734 
00735                     case VT_I2:
00736                     case VT_I4:
00737                         V_VT(pVarResult) = VT_I4;
00738                         V_I4(pVarResult) = value;
00739                         break;
00740 
00741                     case VT_LPSTR:
00742                         if (!(str = msi_alloc(++size * sizeof(WCHAR))))
00743                             ERR("Out of memory\n");
00744                         else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
00745                                                                    NULL, str, &size)) != ERROR_SUCCESS)
00746                             ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
00747                         else
00748                         {
00749                             V_VT(pVarResult) = VT_BSTR;
00750                             V_BSTR(pVarResult) = SysAllocString(str);
00751                         }
00752                         msi_free(str);
00753                         break;
00754 
00755                     case VT_FILETIME:
00756                         FileTimeToLocalFileTime(&ft, &ftlocal);
00757                         FileTimeToSystemTime(&ftlocal, &st);
00758                         SystemTimeToVariantTime(&st, &date);
00759 
00760                         V_VT(pVarResult) = VT_DATE;
00761                         V_DATE(pVarResult) = date;
00762                         break;
00763 
00764                     default:
00765                         ERR("Unhandled variant type %d\n", type);
00766                 }
00767             }
00768             else if (wFlags & DISPATCH_PROPERTYPUT)
00769             {
00770                 UINT posValue = DISPID_PROPERTYPUT;
00771 
00772                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
00773                 if (FAILED(hr)) return hr;
00774                 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
00775                 if (FAILED(hr))
00776                 {
00777                     *puArgErr = posValue;
00778                     return hr;
00779                 }
00780 
00781                 switch (V_VT(&varg1))
00782                 {
00783                     case VT_I2:
00784                     case VT_I4:
00785                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
00786                         break;
00787 
00788                     case VT_DATE:
00789                         VariantTimeToSystemTime(V_DATE(&varg1), &st);
00790                         SystemTimeToFileTime(&st, &ftlocal);
00791                         LocalFileTimeToFileTime(&ftlocal, &ft);
00792                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
00793                         break;
00794 
00795                     case VT_BSTR:
00796                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
00797                         break;
00798 
00799                     default:
00800                         FIXME("Unhandled variant type %d\n", V_VT(&varg1));
00801                         VariantClear(&varg1);
00802                         return DISP_E_EXCEPTION;
00803                 }
00804 
00805                 if (ret != ERROR_SUCCESS)
00806                 {
00807                     ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
00808                     return DISP_E_EXCEPTION;
00809                 }
00810             }
00811             else return DISP_E_MEMBERNOTFOUND;
00812             break;
00813 
00814         case DISPID_SUMMARYINFO_PROPERTYCOUNT:
00815             if (wFlags & DISPATCH_PROPERTYGET) {
00816                 UINT count;
00817                 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
00818                     ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
00819                 else
00820                 {
00821                     V_VT(pVarResult) = VT_I4;
00822                     V_I4(pVarResult) = count;
00823                 }
00824             }
00825             else return DISP_E_MEMBERNOTFOUND;
00826             break;
00827 
00828         default:
00829             return DISP_E_MEMBERNOTFOUND;
00830     }
00831 
00832     VariantClear(&varg1);
00833     VariantClear(&varg0);
00834 
00835     return S_OK;
00836 }
00837 
00838 static HRESULT RecordImpl_Invoke(
00839         AutomationObject* This,
00840         DISPID dispIdMember,
00841         REFIID riid,
00842         LCID lcid,
00843         WORD wFlags,
00844         DISPPARAMS* pDispParams,
00845         VARIANT* pVarResult,
00846         EXCEPINFO* pExcepInfo,
00847         UINT* puArgErr)
00848 {
00849     WCHAR *szString;
00850     DWORD dwLen;
00851     UINT ret;
00852     VARIANTARG varg0, varg1;
00853     HRESULT hr;
00854 
00855     VariantInit(&varg0);
00856     VariantInit(&varg1);
00857 
00858     switch (dispIdMember)
00859     {
00860         case DISPID_RECORD_FIELDCOUNT:
00861             if (wFlags & DISPATCH_PROPERTYGET) {
00862                 V_VT(pVarResult) = VT_I4;
00863                 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
00864             }
00865             else return DISP_E_MEMBERNOTFOUND;
00866             break;
00867 
00868         case DISPID_RECORD_STRINGDATA:
00869             if (wFlags & DISPATCH_PROPERTYGET) {
00870                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
00871                 if (FAILED(hr)) return hr;
00872                 V_VT(pVarResult) = VT_BSTR;
00873                 V_BSTR(pVarResult) = NULL;
00874                 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
00875                 {
00876                     if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
00877                         ERR("Out of memory\n");
00878                     else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
00879                         V_BSTR(pVarResult) = SysAllocString(szString);
00880                     msi_free(szString);
00881                 }
00882                 if (ret != ERROR_SUCCESS)
00883                     ERR("MsiRecordGetString returned %d\n", ret);
00884             } else if (wFlags & DISPATCH_PROPERTYPUT) {
00885                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
00886                 if (FAILED(hr)) return hr;
00887                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
00888                 if (FAILED(hr)) return hr;
00889                 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
00890                 {
00891                     VariantClear(&varg1);
00892                     ERR("MsiRecordSetString returned %d\n", ret);
00893                     return DISP_E_EXCEPTION;
00894                 }
00895             }
00896             else return DISP_E_MEMBERNOTFOUND;
00897             break;
00898 
00899         case DISPID_RECORD_INTEGERDATA:
00900             if (wFlags & DISPATCH_PROPERTYGET) {
00901                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
00902                 if (FAILED(hr)) return hr;
00903                 V_VT(pVarResult) = VT_I4;
00904                 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
00905             } else if (wFlags & DISPATCH_PROPERTYPUT) {
00906                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
00907                 if (FAILED(hr)) return hr;
00908                 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
00909                 if (FAILED(hr)) return hr;
00910                 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
00911                 {
00912                     ERR("MsiRecordSetInteger returned %d\n", ret);
00913                     return DISP_E_EXCEPTION;
00914                 }
00915             }
00916             else return DISP_E_MEMBERNOTFOUND;
00917             break;
00918 
00919          default:
00920             return DISP_E_MEMBERNOTFOUND;
00921     }
00922 
00923     VariantClear(&varg1);
00924     VariantClear(&varg0);
00925 
00926     return S_OK;
00927 }
00928 
00929 static HRESULT create_record(MSIHANDLE msiHandle, IDispatch **disp)
00930 {
00931     AutomationObject *record;
00932     HRESULT hr;
00933 
00934     record = msi_alloc(sizeof(*record));
00935     if (!record) return E_OUTOFMEMORY;
00936 
00937     hr = init_automation_object(record, msiHandle, &DIID_Record, RecordImpl_Invoke, NULL);
00938     if (hr != S_OK)
00939     {
00940         msi_free(record);
00941         return hr;
00942     }
00943 
00944     *disp = &record->IDispatch_iface;
00945 
00946     return hr;
00947 }
00948 
00949 static HRESULT ListImpl_Invoke(
00950         AutomationObject* This,
00951         DISPID dispIdMember,
00952         REFIID riid,
00953         LCID lcid,
00954         WORD wFlags,
00955         DISPPARAMS* pDispParams,
00956         VARIANT* pVarResult,
00957         EXCEPINFO* pExcepInfo,
00958         UINT* puArgErr)
00959 {
00960     ListObject *list = (ListObject*)This;
00961     IUnknown *pUnk = NULL;
00962     HRESULT hr;
00963 
00964     switch (dispIdMember)
00965     {
00966          case DISPID_LIST__NEWENUM:
00967              if (wFlags & DISPATCH_METHOD) {
00968                  V_VT(pVarResult) = VT_UNKNOWN;
00969                  if (SUCCEEDED(hr = create_list_enumerator(list, (LPVOID *)&pUnk)))
00970                      V_UNKNOWN(pVarResult) = pUnk;
00971                  else
00972                      ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
00973              }
00974              else return DISP_E_MEMBERNOTFOUND;
00975              break;
00976 
00977          case DISPID_LIST_ITEM:
00978              if (wFlags & DISPATCH_PROPERTYGET) {
00979                 VARIANTARG index;
00980 
00981                 VariantInit(&index);
00982                 hr = DispGetParam(pDispParams, 0, VT_I4, &index, puArgErr);
00983                 if (FAILED(hr)) return hr;
00984                 if (V_I4(&index) < 0 || V_I4(&index) >= list->count)
00985                     return DISP_E_BADINDEX;
00986                 VariantCopy(pVarResult, &list->data[V_I4(&index)]);
00987             }
00988             else return DISP_E_MEMBERNOTFOUND;
00989             break;
00990 
00991          case DISPID_LIST_COUNT:
00992             if (wFlags & DISPATCH_PROPERTYGET) {
00993                 V_VT(pVarResult) = VT_I4;
00994                 V_I4(pVarResult) = list->count;
00995             }
00996             else return DISP_E_MEMBERNOTFOUND;
00997             break;
00998 
00999          default:
01000             return DISP_E_MEMBERNOTFOUND;
01001     }
01002 
01003     return S_OK;
01004 }
01005 
01006 static void ListImpl_Free(AutomationObject *This)
01007 {
01008     ListObject *list = (ListObject*)This;
01009     int i;
01010 
01011     for (i = 0; i < list->count; i++)
01012         VariantClear(&list->data[i]);
01013     msi_free(list->data);
01014 }
01015 
01016 static HRESULT get_products_count(const WCHAR *product, int *len)
01017 {
01018     int i = 0;
01019 
01020     while (1)
01021     {
01022         WCHAR dataW[GUID_SIZE];
01023         UINT ret;
01024 
01025         /* all or related only */
01026         if (product)
01027             ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
01028         else
01029             ret = MsiEnumProductsW(i, dataW);
01030 
01031         if (ret == ERROR_NO_MORE_ITEMS) break;
01032 
01033         if (ret != ERROR_SUCCESS)
01034             return DISP_E_EXCEPTION;
01035 
01036         i++;
01037     }
01038 
01039     *len = i;
01040 
01041     return S_OK;
01042 }
01043 
01044 static HRESULT create_list(const WCHAR *product, IDispatch **dispatch)
01045 {
01046     ListObject *list;
01047     HRESULT hr;
01048     int i;
01049 
01050     list = msi_alloc_zero(sizeof(ListObject));
01051     if (!list) return E_OUTOFMEMORY;
01052 
01053     hr = init_automation_object(&list->autoobj, 0, &DIID_StringList, ListImpl_Invoke, ListImpl_Free);
01054     if (hr != S_OK)
01055     {
01056         msi_free(list);
01057         return hr;
01058     }
01059 
01060     *dispatch = &list->autoobj.IDispatch_iface;
01061 
01062     hr = get_products_count(product, &list->count);
01063     if (hr != S_OK)
01064     {
01065         IDispatch_Release(*dispatch);
01066         return hr;
01067     }
01068 
01069     list->data = msi_alloc(list->count*sizeof(VARIANT));
01070     if (!list->data)
01071     {
01072         IDispatch_Release(*dispatch);
01073         return E_OUTOFMEMORY;
01074     }
01075 
01076     for (i = 0; i < list->count; i++)
01077     {
01078         WCHAR dataW[GUID_SIZE];
01079         UINT ret;
01080 
01081         /* all or related only */
01082         if (product)
01083             ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
01084         else
01085             ret = MsiEnumProductsW(i, dataW);
01086 
01087         if (ret == ERROR_NO_MORE_ITEMS) break;
01088 
01089         V_VT(&list->data[i]) = VT_BSTR;
01090         V_BSTR(&list->data[i]) = SysAllocString(dataW);
01091     }
01092 
01093     return S_OK;
01094 }
01095 
01096 static HRESULT ViewImpl_Invoke(
01097         AutomationObject* This,
01098         DISPID dispIdMember,
01099         REFIID riid,
01100         LCID lcid,
01101         WORD wFlags,
01102         DISPPARAMS* pDispParams,
01103         VARIANT* pVarResult,
01104         EXCEPINFO* pExcepInfo,
01105         UINT* puArgErr)
01106 {
01107     MSIHANDLE msiHandle;
01108     UINT ret;
01109     VARIANTARG varg0, varg1;
01110     HRESULT hr;
01111 
01112     VariantInit(&varg0);
01113     VariantInit(&varg1);
01114 
01115     switch (dispIdMember)
01116     {
01117         case DISPID_VIEW_EXECUTE:
01118             if (wFlags & DISPATCH_METHOD)
01119             {
01120                 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
01121                 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
01122                     MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
01123                 else
01124                     MsiViewExecute(This->msiHandle, 0);
01125             }
01126             else return DISP_E_MEMBERNOTFOUND;
01127             break;
01128 
01129         case DISPID_VIEW_FETCH:
01130             if (wFlags & DISPATCH_METHOD)
01131             {
01132                 V_VT(pVarResult) = VT_DISPATCH;
01133                 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
01134                 {
01135                     IDispatch *dispatch = NULL;
01136 
01137                     if (SUCCEEDED(hr = create_record(msiHandle, &dispatch)))
01138                         V_DISPATCH(pVarResult) = dispatch;
01139                     else
01140                         ERR("Failed to create Record object, hresult 0x%08x\n", hr);
01141                 }
01142                 else if (ret == ERROR_NO_MORE_ITEMS)
01143                     V_DISPATCH(pVarResult) = NULL;
01144                 else
01145                 {
01146                     ERR("MsiViewFetch returned %d\n", ret);
01147                     return DISP_E_EXCEPTION;
01148                 }
01149             }
01150             else return DISP_E_MEMBERNOTFOUND;
01151             break;
01152 
01153         case DISPID_VIEW_MODIFY:
01154             if (wFlags & DISPATCH_METHOD)
01155             {
01156                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
01157                 if (FAILED(hr)) return hr;
01158                 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
01159                 if (FAILED(hr)) return hr;
01160                 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
01161                 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
01162                 {
01163                     VariantClear(&varg1);
01164                     ERR("MsiViewModify returned %d\n", ret);
01165                     return DISP_E_EXCEPTION;
01166                 }
01167             }
01168             else return DISP_E_MEMBERNOTFOUND;
01169             break;
01170 
01171         case DISPID_VIEW_CLOSE:
01172             if (wFlags & DISPATCH_METHOD)
01173             {
01174                 MsiViewClose(This->msiHandle);
01175             }
01176             else return DISP_E_MEMBERNOTFOUND;
01177             break;
01178 
01179          default:
01180             return DISP_E_MEMBERNOTFOUND;
01181     }
01182 
01183     VariantClear(&varg1);
01184     VariantClear(&varg0);
01185 
01186     return S_OK;
01187 }
01188 
01189 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
01190                                             DISPPARAMS* pDispParams,
01191                                             VARIANT* pVarResult,
01192                                             EXCEPINFO* pExcepInfo,
01193                                             UINT* puArgErr)
01194 {
01195     if (!(wFlags & DISPATCH_METHOD))
01196         return DISP_E_MEMBERNOTFOUND;
01197 
01198     FIXME("\n");
01199 
01200     VariantInit(pVarResult);
01201     return S_OK;
01202 }
01203 
01204 static HRESULT DatabaseImpl_Invoke(
01205         AutomationObject* This,
01206         DISPID dispIdMember,
01207         REFIID riid,
01208         LCID lcid,
01209         WORD wFlags,
01210         DISPPARAMS* pDispParams,
01211         VARIANT* pVarResult,
01212         EXCEPINFO* pExcepInfo,
01213         UINT* puArgErr)
01214 {
01215     IDispatch *dispatch = NULL;
01216     MSIHANDLE msiHandle;
01217     UINT ret;
01218     VARIANTARG varg0, varg1;
01219     HRESULT hr;
01220 
01221     VariantInit(&varg0);
01222     VariantInit(&varg1);
01223 
01224     switch (dispIdMember)
01225     {
01226         case DISPID_DATABASE_SUMMARYINFORMATION:
01227             if (wFlags & DISPATCH_PROPERTYGET)
01228             {
01229                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
01230                 if (FAILED(hr))
01231                     V_I4(&varg0) = 0;
01232 
01233                 V_VT(pVarResult) = VT_DISPATCH;
01234                 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
01235                 {
01236                     hr = create_summaryinfo(msiHandle, &dispatch);
01237                     if (SUCCEEDED(hr))
01238                         V_DISPATCH(pVarResult) = dispatch;
01239                     else
01240                         ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
01241                 }
01242                 else
01243                 {
01244                     ERR("MsiGetSummaryInformation returned %d\n", ret);
01245                     return DISP_E_EXCEPTION;
01246                 }
01247             }
01248             else return DISP_E_MEMBERNOTFOUND;
01249             break;
01250 
01251         case DISPID_DATABASE_OPENVIEW:
01252             if (wFlags & DISPATCH_METHOD)
01253             {
01254                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
01255                 if (FAILED(hr)) return hr;
01256                 V_VT(pVarResult) = VT_DISPATCH;
01257                 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
01258                 {
01259                     if (SUCCEEDED(hr = create_view(msiHandle, &dispatch)))
01260                         V_DISPATCH(pVarResult) = dispatch;
01261                     else
01262                         ERR("Failed to create View object, hresult 0x%08x\n", hr);
01263                 }
01264                 else
01265                 {
01266                     VariantClear(&varg0);
01267                     ERR("MsiDatabaseOpenView returned %d\n", ret);
01268                     return DISP_E_EXCEPTION;
01269                 }
01270             }
01271             else return DISP_E_MEMBERNOTFOUND;
01272             break;
01273 
01274         case DISPID_INSTALLER_LASTERRORRECORD:
01275             return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
01276                                                 pVarResult, pExcepInfo,
01277                                                 puArgErr);
01278 
01279          default:
01280             return DISP_E_MEMBERNOTFOUND;
01281     }
01282 
01283     VariantClear(&varg1);
01284     VariantClear(&varg0);
01285 
01286     return S_OK;
01287 }
01288 
01289 static HRESULT SessionImpl_Invoke(
01290         AutomationObject* This,
01291         DISPID dispIdMember,
01292         REFIID riid,
01293         LCID lcid,
01294         WORD wFlags,
01295         DISPPARAMS* pDispParams,
01296         VARIANT* pVarResult,
01297         EXCEPINFO* pExcepInfo,
01298         UINT* puArgErr)
01299 {
01300     SessionObject *session = (SessionObject*)This;
01301     WCHAR *szString;
01302     DWORD dwLen;
01303     MSIHANDLE msiHandle;
01304     LANGID langId;
01305     UINT ret;
01306     INSTALLSTATE iInstalled, iAction;
01307     VARIANTARG varg0, varg1;
01308     HRESULT hr;
01309 
01310     VariantInit(&varg0);
01311     VariantInit(&varg1);
01312 
01313     switch (dispIdMember)
01314     {
01315         case DISPID_SESSION_INSTALLER:
01316             if (wFlags & DISPATCH_PROPERTYGET) {
01317                 V_VT(pVarResult) = VT_DISPATCH;
01318                 IDispatch_AddRef(session->installer);
01319                 V_DISPATCH(pVarResult) = session->installer;
01320             }
01321             else return DISP_E_MEMBERNOTFOUND;
01322             break;
01323 
01324         case DISPID_SESSION_PROPERTY:
01325             if (wFlags & DISPATCH_PROPERTYGET) {
01326                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
01327                 if (FAILED(hr)) return hr;
01328                 V_VT(pVarResult) = VT_BSTR;
01329                 V_BSTR(pVarResult) = NULL;
01330                 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
01331                 {
01332                     if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
01333                         ERR("Out of memory\n");
01334                     else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
01335                         V_BSTR(pVarResult) = SysAllocString(szString);
01336                     msi_free(szString);
01337                 }
01338                 if (ret != ERROR_SUCCESS)
01339                     ERR("MsiGetProperty returned %d\n", ret);
01340             } else if (wFlags & DISPATCH_PROPERTYPUT) {
01341                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
01342                 if (FAILED(hr)) return hr;
01343                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
01344                 if (FAILED(hr)) {
01345                     VariantClear(&varg0);
01346                     return hr;
01347                 }
01348                 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
01349                 {
01350                     VariantClear(&varg0);
01351                     VariantClear(&varg1);
01352                     ERR("MsiSetProperty returned %d\n", ret);
01353                     return DISP_E_EXCEPTION;
01354                 }
01355             }
01356             else return DISP_E_MEMBERNOTFOUND;
01357             break;
01358 
01359         case DISPID_SESSION_LANGUAGE:
01360             if (wFlags & DISPATCH_PROPERTYGET) {
01361                 langId = MsiGetLanguage(This->msiHandle);
01362                 V_VT(pVarResult) = VT_I4;
01363                 V_I4(pVarResult) = langId;
01364             }
01365             else return DISP_E_MEMBERNOTFOUND;
01366             break;
01367 
01368         case DISPID_SESSION_MODE:
01369             if (wFlags & DISPATCH_PROPERTYGET) {
01370                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
01371                 if (FAILED(hr)) return hr;
01372                 V_VT(pVarResult) = VT_BOOL;
01373                 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
01374             } else if (wFlags & DISPATCH_PROPERTYPUT) {
01375                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
01376                 if (FAILED(hr)) return hr;
01377                 hr = DispGetParam(pDispParams, 1, VT_BOOL, &varg1, puArgErr);
01378                 if (FAILED(hr)) return hr;
01379                 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
01380                 {
01381                     ERR("MsiSetMode returned %d\n", ret);
01382                     return DISP_E_EXCEPTION;
01383                 }
01384             }
01385             else return DISP_E_MEMBERNOTFOUND;
01386             break;
01387 
01388         case DISPID_SESSION_DATABASE:
01389             if (wFlags & DISPATCH_PROPERTYGET) {
01390                 V_VT(pVarResult) = VT_DISPATCH;
01391                 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
01392                 {
01393                     IDispatch *dispatch;
01394 
01395                     if (SUCCEEDED(hr = create_database(msiHandle, &dispatch)))
01396                         V_DISPATCH(pVarResult) = dispatch;
01397                     else
01398                         ERR("Failed to create Database object, hresult 0x%08x\n", hr);
01399                 }
01400                 else
01401                 {
01402                     ERR("MsiGetActiveDatabase failed\n");
01403                     return DISP_E_EXCEPTION;
01404                 }
01405             }
01406             else return DISP_E_MEMBERNOTFOUND;
01407             break;
01408 
01409         case DISPID_SESSION_DOACTION:
01410             if (wFlags & DISPATCH_METHOD) {
01411                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
01412                 if (FAILED(hr)) return hr;
01413                 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
01414                 V_VT(pVarResult) = VT_I4;
01415                 switch (ret)
01416                 {
01417                     case ERROR_FUNCTION_NOT_CALLED:
01418                         V_I4(pVarResult) = msiDoActionStatusNoAction;
01419                         break;
01420                     case ERROR_SUCCESS:
01421                         V_I4(pVarResult) = msiDoActionStatusSuccess;
01422                         break;
01423                     case ERROR_INSTALL_USEREXIT:
01424                         V_I4(pVarResult) = msiDoActionStatusUserExit;
01425                         break;
01426                     case ERROR_INSTALL_FAILURE:
01427                         V_I4(pVarResult) = msiDoActionStatusFailure;
01428                         break;
01429                     case ERROR_INSTALL_SUSPEND:
01430                         V_I4(pVarResult) = msiDoActionStatusSuspend;
01431                         break;
01432                     case ERROR_MORE_DATA:
01433                         V_I4(pVarResult) = msiDoActionStatusFinished;
01434                         break;
01435                     case ERROR_INVALID_HANDLE_STATE:
01436                         V_I4(pVarResult) = msiDoActionStatusWrongState;
01437                         break;
01438                     case ERROR_INVALID_DATA:
01439                         V_I4(pVarResult) = msiDoActionStatusBadActionData;
01440                         break;
01441                     default:
01442                         VariantClear(&varg0);
01443                         FIXME("MsiDoAction returned unhandled value %d\n", ret);
01444                         return DISP_E_EXCEPTION;
01445                 }
01446             }
01447             else return DISP_E_MEMBERNOTFOUND;
01448             break;
01449 
01450         case DISPID_SESSION_EVALUATECONDITION:
01451             if (wFlags & DISPATCH_METHOD) {
01452                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
01453                 if (FAILED(hr)) return hr;
01454                 V_VT(pVarResult) = VT_I4;
01455                 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
01456             }
01457             else return DISP_E_MEMBERNOTFOUND;
01458             break;
01459 
01460         case DISPID_SESSION_MESSAGE:
01461             if(!(wFlags & DISPATCH_METHOD))
01462                 return DISP_E_MEMBERNOTFOUND;
01463 
01464             hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
01465             if (FAILED(hr)) return hr;
01466             hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
01467             if (FAILED(hr)) return hr;
01468 
01469             V_VT(pVarResult) = VT_I4;
01470             V_I4(pVarResult) =
01471                 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
01472             break;
01473 
01474         case DISPID_SESSION_SETINSTALLLEVEL:
01475             if (wFlags & DISPATCH_METHOD) {
01476                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
01477                 if (FAILED(hr)) return hr;
01478                 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
01479                 {
01480                     ERR("MsiSetInstallLevel returned %d\n", ret);
01481                     return DISP_E_EXCEPTION;
01482                 }
01483             }
01484             else return DISP_E_MEMBERNOTFOUND;
01485             break;
01486 
01487         case DISPID_SESSION_FEATURECURRENTSTATE:
01488             if (wFlags & DISPATCH_PROPERTYGET) {
01489                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
01490                 if (FAILED(hr)) return hr;
01491                 V_VT(pVarResult) = VT_I4;
01492                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
01493                     V_I4(pVarResult) = iInstalled;
01494                 else
01495                 {
01496                     ERR("MsiGetFeatureState returned %d\n", ret);
01497                     V_I4(pVarResult) = msiInstallStateUnknown;
01498                 }
01499             }
01500             else return DISP_E_MEMBERNOTFOUND;
01501             break;
01502 
01503         case DISPID_SESSION_FEATUREREQUESTSTATE:
01504             if (wFlags & DISPATCH_PROPERTYGET) {
01505                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
01506                 if (FAILED(hr)) return hr;
01507                 V_VT(pVarResult) = VT_I4;
01508                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
01509                     V_I4(pVarResult) = iAction;
01510                 else
01511                 {
01512                     ERR("MsiGetFeatureState returned %d\n", ret);
01513                     V_I4(pVarResult) = msiInstallStateUnknown;
01514                 }
01515             } else if (wFlags & DISPATCH_PROPERTYPUT) {
01516                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
01517                 if (FAILED(hr)) return hr;
01518                 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
01519                 if (FAILED(hr)) {
01520                     VariantClear(&varg0);
01521                     return hr;
01522                 }
01523                 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
01524                 {
01525                     VariantClear(&varg0);
01526                     ERR("MsiSetFeatureState returned %d\n", ret);
01527                     return DISP_E_EXCEPTION;
01528                 }
01529             }
01530             else return DISP_E_MEMBERNOTFOUND;
01531             break;
01532 
01533          default:
01534             return DISP_E_MEMBERNOTFOUND;
01535     }
01536 
01537     VariantClear(&varg1);
01538     VariantClear(&varg0);
01539 
01540     return S_OK;
01541 }
01542 
01543 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
01544  * registry value type. Used by Installer::RegistryValue. */
01545 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
01546 {
01547     static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
01548     static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
01549     WCHAR *szString = (WCHAR *)lpData;
01550     LPWSTR szNewString = NULL;
01551     DWORD dwNewSize = 0;
01552     int idx;
01553 
01554     switch (dwType)
01555     {
01556         /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
01557         case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
01558             idx = (dwSize/sizeof(WCHAR))-1;
01559             while (idx >= 0 && !szString[idx]) idx--;
01560             for (; idx >= 0; idx--)
01561                 if (!szString[idx]) szString[idx] = '\n';
01562             /* fall through */
01563         case REG_SZ:
01564             V_VT(pVarResult) = VT_BSTR;
01565             V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
01566             break;
01567 
01568         case REG_EXPAND_SZ:
01569             if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
01570                 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
01571             else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
01572                 ERR("Out of memory\n");
01573             else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
01574                 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
01575             else
01576             {
01577                 V_VT(pVarResult) = VT_BSTR;
01578                 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
01579             }
01580             msi_free(szNewString);
01581             break;
01582 
01583         case REG_DWORD:
01584             V_VT(pVarResult) = VT_I4;
01585             V_I4(pVarResult) = *((DWORD *)lpData);
01586             break;
01587 
01588         case REG_QWORD:
01589             V_VT(pVarResult) = VT_BSTR;
01590             V_BSTR(pVarResult) = SysAllocString(szREG_);   /* Weird string, don't know why native returns it */
01591             break;
01592 
01593         case REG_BINARY:
01594             V_VT(pVarResult) = VT_BSTR;
01595             V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
01596             break;
01597 
01598         case REG_NONE:
01599             V_VT(pVarResult) = VT_EMPTY;
01600             break;
01601 
01602         default:
01603             FIXME("Unhandled registry value type %d\n", dwType);
01604     }
01605 }
01606 
01607 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
01608                                           DISPPARAMS* pDispParams,
01609                                           VARIANT* pVarResult,
01610                                           EXCEPINFO* pExcepInfo,
01611                                           UINT* puArgErr)
01612 {
01613     HRESULT hr;
01614     VARIANTARG varg0;
01615     MSIHANDLE hrec;
01616     IDispatch* dispatch;
01617 
01618     if (!(wFlags & DISPATCH_METHOD))
01619         return DISP_E_MEMBERNOTFOUND;
01620 
01621     VariantInit(&varg0);
01622     hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
01623     if (FAILED(hr))
01624         return hr;
01625 
01626     V_VT(pVarResult) = VT_DISPATCH;
01627 
01628     hrec = MsiCreateRecord(V_I4(&varg0));
01629     if (!hrec)
01630         return DISP_E_EXCEPTION;
01631 
01632     hr = create_record(hrec, &dispatch);
01633     if (SUCCEEDED(hr))
01634         V_DISPATCH(pVarResult) = dispatch;
01635 
01636     return hr;
01637 }
01638 
01639 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
01640                                          WORD wFlags,
01641                                          DISPPARAMS* pDispParams,
01642                                          VARIANT* pVarResult,
01643                                          EXCEPINFO* pExcepInfo,
01644                                          UINT* puArgErr)
01645 {
01646     UINT ret;
01647     HRESULT hr;
01648     MSIHANDLE hpkg;
01649     IDispatch* dispatch;
01650     VARIANTARG varg0, varg1;
01651 
01652     if (!(wFlags & DISPATCH_METHOD))
01653         return DISP_E_MEMBERNOTFOUND;
01654 
01655     if (pDispParams->cArgs == 0)
01656         return DISP_E_TYPEMISMATCH;
01657 
01658     if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
01659         return DISP_E_TYPEMISMATCH;
01660 
01661     VariantInit(&varg0);
01662     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
01663     if (FAILED(hr))
01664         return hr;
01665 
01666     VariantInit(&varg1);
01667     if (pDispParams->cArgs == 2)
01668     {
01669         hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
01670         if (FAILED(hr))
01671             goto done;
01672     }
01673     else
01674     {
01675         V_VT(&varg1) = VT_I4;
01676         V_I4(&varg1) = 0;
01677     }
01678 
01679     V_VT(pVarResult) = VT_DISPATCH;
01680 
01681     ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
01682     if (ret != ERROR_SUCCESS)
01683     {
01684         hr = DISP_E_EXCEPTION;
01685         goto done;
01686     }
01687 
01688     hr = create_session(hpkg, &This->IDispatch_iface, &dispatch);
01689     if (SUCCEEDED(hr))
01690         V_DISPATCH(pVarResult) = dispatch;
01691 
01692 done:
01693     VariantClear(&varg0);
01694     VariantClear(&varg1);
01695     return hr;
01696 }
01697 
01698 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
01699                                          DISPPARAMS* pDispParams,
01700                                          VARIANT* pVarResult,
01701                                          EXCEPINFO* pExcepInfo,
01702                                          UINT* puArgErr)
01703 {
01704     HRESULT hr;
01705     VARIANTARG varg0;
01706 
01707     if (!(wFlags & DISPATCH_METHOD))
01708         return DISP_E_MEMBERNOTFOUND;
01709 
01710     VariantInit(&varg0);
01711     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
01712     if (FAILED(hr))
01713         return hr;
01714 
01715     FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
01716 
01717     VariantInit(pVarResult);
01718 
01719     VariantClear(&varg0);
01720     return S_OK;
01721 }
01722 
01723 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
01724                                           DISPPARAMS* pDispParams,
01725                                           VARIANT* pVarResult,
01726                                           EXCEPINFO* pExcepInfo,
01727                                           UINT* puArgErr)
01728 {
01729     UINT ret;
01730     HRESULT hr;
01731     MSIHANDLE hdb;
01732     IDispatch* dispatch;
01733     VARIANTARG varg0, varg1;
01734 
01735     if (!(wFlags & DISPATCH_METHOD))
01736         return DISP_E_MEMBERNOTFOUND;
01737 
01738     VariantInit(&varg0);
01739     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
01740     if (FAILED(hr))
01741         return hr;
01742 
01743     VariantInit(&varg1);
01744     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
01745     if (FAILED(hr))
01746         goto done;
01747 
01748     V_VT(pVarResult) = VT_DISPATCH;
01749 
01750     ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
01751     if (ret != ERROR_SUCCESS)
01752     {
01753         hr = DISP_E_EXCEPTION;
01754         goto done;
01755     }
01756 
01757     hr = create_database(hdb, &dispatch);
01758     if (SUCCEEDED(hr))
01759         V_DISPATCH(pVarResult) = dispatch;
01760 
01761 done:
01762     VariantClear(&varg0);
01763     VariantClear(&varg1);
01764     return hr;
01765 }
01766 
01767 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
01768                                                 DISPPARAMS* pDispParams,
01769                                                 VARIANT* pVarResult,
01770                                                 EXCEPINFO* pExcepInfo,
01771                                                 UINT* puArgErr)
01772 {
01773     if (!(wFlags & DISPATCH_METHOD))
01774         return DISP_E_MEMBERNOTFOUND;
01775 
01776     FIXME("\n");
01777 
01778     VariantInit(pVarResult);
01779     return S_OK;
01780 }
01781 
01782 static HRESULT InstallerImpl_UILevel(WORD wFlags,
01783                                      DISPPARAMS* pDispParams,
01784                                      VARIANT* pVarResult,
01785                                      EXCEPINFO* pExcepInfo,
01786                                      UINT* puArgErr)
01787 {
01788     HRESULT hr;
01789     VARIANTARG varg0;
01790     INSTALLUILEVEL ui;
01791 
01792     if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
01793         return DISP_E_MEMBERNOTFOUND;
01794 
01795     if (wFlags & DISPATCH_PROPERTYPUT)
01796     {
01797         VariantInit(&varg0);
01798         hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
01799         if (FAILED(hr))
01800             return hr;
01801 
01802         ui = MsiSetInternalUI(V_I4(&varg0), NULL);
01803         if (ui == INSTALLUILEVEL_NOCHANGE)
01804             return DISP_E_EXCEPTION;
01805     }
01806     else if (wFlags & DISPATCH_PROPERTYGET)
01807     {
01808         ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
01809         if (ui == INSTALLUILEVEL_NOCHANGE)
01810             return DISP_E_EXCEPTION;
01811 
01812         V_VT(pVarResult) = VT_I4;
01813         V_I4(pVarResult) = ui;
01814     }
01815 
01816     return S_OK;
01817 }
01818 
01819 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
01820                                        DISPPARAMS* pDispParams,
01821                                        VARIANT* pVarResult,
01822                                        EXCEPINFO* pExcepInfo,
01823                                        UINT* puArgErr)
01824 {
01825     if (!(wFlags & DISPATCH_METHOD))
01826         return DISP_E_MEMBERNOTFOUND;
01827 
01828     FIXME("\n");
01829 
01830     VariantInit(pVarResult);
01831     return S_OK;
01832 }
01833 
01834 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
01835                                             DISPPARAMS* pDispParams,
01836                                             VARIANT* pVarResult,
01837                                             EXCEPINFO* pExcepInfo,
01838                                             UINT* puArgErr)
01839 {
01840     UINT ret;
01841     HRESULT hr;
01842     VARIANTARG varg0, varg1;
01843 
01844     if (!(wFlags & DISPATCH_METHOD))
01845         return DISP_E_MEMBERNOTFOUND;
01846 
01847     VariantInit(&varg0);
01848     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
01849     if (FAILED(hr))
01850         return hr;
01851 
01852     VariantInit(&varg1);
01853     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
01854     if (FAILED(hr))
01855         goto done;
01856 
01857     ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
01858     if (ret != ERROR_SUCCESS)
01859     {
01860         hr = DISP_E_EXCEPTION;
01861         goto done;
01862     }
01863 
01864 done:
01865     VariantClear(&varg0);
01866     VariantClear(&varg1);
01867     return hr;
01868 }
01869 
01870 static HRESULT InstallerImpl_Version(WORD wFlags,
01871                                      VARIANT* pVarResult,
01872                                      EXCEPINFO* pExcepInfo,
01873                                      UINT* puArgErr)
01874 {
01875     HRESULT hr;
01876     DLLVERSIONINFO verinfo;
01877     WCHAR version[MAX_PATH];
01878 
01879     static const WCHAR format[] = {
01880         '%','d','.','%','d','.','%','d','.','%','d',0};
01881 
01882     if (!(wFlags & DISPATCH_PROPERTYGET))
01883         return DISP_E_MEMBERNOTFOUND;
01884 
01885     verinfo.cbSize = sizeof(DLLVERSIONINFO);
01886     hr = DllGetVersion(&verinfo);
01887     if (FAILED(hr))
01888         return hr;
01889 
01890     sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
01891              verinfo.dwBuildNumber, verinfo.dwPlatformID);
01892 
01893     V_VT(pVarResult) = VT_BSTR;
01894     V_BSTR(pVarResult) = SysAllocString(version);
01895     return S_OK;
01896 }
01897 
01898 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
01899                                              DISPPARAMS* pDispParams,
01900                                              VARIANT* pVarResult,
01901                                              EXCEPINFO* pExcepInfo,
01902                                              UINT* puArgErr)
01903 {
01904     if (!(wFlags & DISPATCH_METHOD))
01905         return DISP_E_MEMBERNOTFOUND;
01906 
01907     FIXME("\n");
01908 
01909     VariantInit(pVarResult);
01910     return S_OK;
01911 }
01912 
01913 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
01914                                            DISPPARAMS* pDispParams,
01915                                            VARIANT* pVarResult,
01916                                            EXCEPINFO* pExcepInfo,
01917                                            UINT* puArgErr)
01918 {
01919     UINT ret;
01920     HKEY hkey = NULL;
01921     HRESULT hr;
01922     UINT posValue;
01923     DWORD type, size;
01924     LPWSTR szString = NULL;
01925     VARIANTARG varg0, varg1, varg2;
01926 
01927     if (!(wFlags & DISPATCH_METHOD))
01928         return DISP_E_MEMBERNOTFOUND;
01929 
01930     VariantInit(&varg0);
01931     hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
01932     if (FAILED(hr))
01933         return hr;
01934 
01935     VariantInit(&varg1);
01936     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
01937     if (FAILED(hr))
01938         goto done;
01939 
01940     /* Save valuePos so we can save puArgErr if we are unable to do our type
01941      * conversions.
01942      */
01943     posValue = 2;
01944     VariantInit(&varg2);
01945     hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
01946     if (FAILED(hr))
01947         goto done;
01948 
01949     if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
01950         V_I4(&varg0) <= REG_INDEX_DYN_DATA)
01951     {
01952         V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
01953     }
01954 
01955     ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
01956 
01957     /* Only VT_EMPTY case can do anything if the key doesn't exist. */
01958     if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
01959     {
01960         hr = DISP_E_BADINDEX;
01961         goto done;
01962     }
01963 
01964     /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
01965     switch (V_VT(&varg2))
01966     {
01967         /* Return VT_BOOL clarifying whether registry key exists or not. */
01968         case VT_EMPTY:
01969             V_VT(pVarResult) = VT_BOOL;
01970             V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
01971             break;
01972 
01973         /* Return the value of specified key if it exists. */
01974         case VT_BSTR:
01975             ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
01976                                    NULL, NULL, NULL, &size);
01977             if (ret != ERROR_SUCCESS)
01978             {
01979                 hr = DISP_E_BADINDEX;
01980                 goto done;
01981             }
01982 
01983             szString = msi_alloc(size);
01984             if (!szString)
01985             {
01986                 hr = E_OUTOFMEMORY;
01987                 goto done;
01988             }
01989 
01990             ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
01991                                    &type, (LPBYTE)szString, &size);
01992             if (ret != ERROR_SUCCESS)
01993             {
01994                 msi_free(szString);
01995                 hr = DISP_E_BADINDEX;
01996                 goto done;
01997             }
01998 
01999             variant_from_registry_value(pVarResult, type,
02000                                         (LPBYTE)szString, size);
02001             msi_free(szString);
02002             break;
02003 
02004         /* Try to make it into VT_I4, can use VariantChangeType for this. */
02005         default:
02006             hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
02007             if (FAILED(hr))
02008             {
02009                 if (hr == DISP_E_TYPEMISMATCH)
02010                     *puArgErr = posValue;
02011 
02012                 goto done;
02013             }
02014 
02015             /* Retrieve class name or maximum value name or subkey name size. */
02016             if (!V_I4(&varg2))
02017                 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
02018                                        NULL, NULL, NULL, NULL, NULL, NULL);
02019             else if (V_I4(&varg2) > 0)
02020                 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
02021                                        NULL, NULL, &size, NULL, NULL, NULL);
02022             else /* V_I4(&varg2) < 0 */
02023                 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
02024                                        NULL, NULL, NULL, NULL, NULL, NULL);
02025 
02026             if (ret != ERROR_SUCCESS)
02027                 goto done;
02028 
02029             szString = msi_alloc(++size * sizeof(WCHAR));
02030             if (!szString)
02031             {
02032                 hr = E_OUTOFMEMORY;
02033                 goto done;
02034             }
02035 
02036             if (!V_I4(&varg2))
02037                 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
02038                                        NULL, NULL, NULL, NULL, NULL, NULL);
02039             else if (V_I4(&varg2) > 0)
02040                 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
02041                                     &size, 0, 0, NULL, NULL);
02042             else /* V_I4(&varg2) < 0 */
02043                 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
02044 
02045             if (ret == ERROR_SUCCESS)
02046             {
02047                 V_VT(pVarResult) = VT_BSTR;
02048                 V_BSTR(pVarResult) = SysAllocString(szString);
02049             }
02050 
02051             msi_free(szString);
02052     }
02053 
02054 done:
02055     VariantClear(&varg0);
02056     VariantClear(&varg1);
02057     VariantClear(&varg2);
02058     RegCloseKey(hkey);
02059     return hr;
02060 }
02061 
02062 static HRESULT InstallerImpl_Environment(WORD wFlags,
02063                                          DISPPARAMS* pDispParams,
02064                                          VARIANT* pVarResult,
02065                                          EXCEPINFO* pExcepInfo,
02066                                          UINT* puArgErr)
02067 {
02068     if (!(wFlags & DISPATCH_METHOD))
02069         return DISP_E_MEMBERNOTFOUND;
02070 
02071     FIXME("\n");
02072 
02073     VariantInit(pVarResult);
02074     return S_OK;
02075 }
02076 
02077 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
02078                                             DISPPARAMS* pDispParams,
02079                                             VARIANT* pVarResult,
02080                                             EXCEPINFO* pExcepInfo,
02081                                             UINT* puArgErr)
02082 {
02083     if (!(wFlags & DISPATCH_METHOD))
02084         return DISP_E_MEMBERNOTFOUND;
02085 
02086     FIXME("\n");
02087 
02088     VariantInit(pVarResult);
02089     return S_OK;
02090 }
02091 
02092 static HRESULT InstallerImpl_FileSize(WORD wFlags,
02093                                       DISPPARAMS* pDispParams,
02094                                       VARIANT* pVarResult,
02095                                       EXCEPINFO* pExcepInfo,
02096                                       UINT* puArgErr)
02097 {
02098     if (!(wFlags & DISPATCH_METHOD))
02099         return DISP_E_MEMBERNOTFOUND;
02100 
02101     FIXME("\n");
02102 
02103     VariantInit(pVarResult);
02104     return S_OK;
02105 }
02106 
02107 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
02108                                          DISPPARAMS* pDispParams,
02109                                          VARIANT* pVarResult,
02110                                          EXCEPINFO* pExcepInfo,
02111                                          UINT* puArgErr)
02112 {
02113     if (!(wFlags & DISPATCH_METHOD))
02114         return DISP_E_MEMBERNOTFOUND;
02115 
02116     FIXME("\n");
02117 
02118     VariantInit(pVarResult);
02119     return S_OK;
02120 }
02121 
02122 static HRESULT InstallerImpl_ProductState(WORD wFlags,
02123                                           DISPPARAMS* pDispParams,
02124                                           VARIANT* pVarResult,
02125                                           EXCEPINFO* pExcepInfo,
02126                                           UINT* puArgErr)
02127 {
02128     HRESULT hr;
02129     VARIANTARG varg0;
02130 
02131     if (!(wFlags & DISPATCH_PROPERTYGET))
02132         return DISP_E_MEMBERNOTFOUND;
02133 
02134     VariantInit(&varg0);
02135     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
02136     if (FAILED(hr))
02137         return hr;
02138 
02139     V_VT(pVarResult) = VT_I4;
02140     V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
02141 
02142     VariantClear(&varg0);
02143     return S_OK;
02144 }
02145 
02146 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
02147                                          DISPPARAMS* pDispParams,
02148                                          VARIANT* pVarResult,
02149                                          EXCEPINFO* pExcepInfo,
02150                                          UINT* puArgErr)
02151 {
02152     UINT ret;
02153     HRESULT hr;
02154     DWORD size;
02155     LPWSTR str = NULL;
02156     VARIANTARG varg0, varg1;
02157 
02158     if (!(wFlags & DISPATCH_PROPERTYGET))
02159         return DISP_E_MEMBERNOTFOUND;
02160 
02161     VariantInit(&varg0);
02162     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
02163     if (FAILED(hr))
02164         return hr;
02165 
02166     VariantInit(&varg1);
02167     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
02168     if (FAILED(hr))
02169         goto done;
02170 
02171     V_VT(pVarResult) = VT_BSTR;
02172     V_BSTR(pVarResult) = NULL;
02173 
02174     ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
02175     if (ret != ERROR_SUCCESS)
02176     {
02177         hr = DISP_E_EXCEPTION;
02178         goto done;
02179     }
02180 
02181     str = msi_alloc(++size * sizeof(WCHAR));
02182     if (!str)
02183     {
02184         hr = E_OUTOFMEMORY;
02185         goto done;
02186     }
02187 
02188     ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
02189     if (ret != ERROR_SUCCESS)
02190     {
02191         hr = DISP_E_EXCEPTION;
02192         goto done;
02193     }
02194 
02195     V_BSTR(pVarResult) = SysAllocString(str);
02196     hr = S_OK;
02197 
02198 done:
02199     msi_free(str);
02200     VariantClear(&varg0);
02201     VariantClear(&varg1);
02202     return hr;
02203 }
02204 
02205 static HRESULT InstallerImpl_Products(WORD flags,
02206                                       DISPPARAMS* pDispParams,
02207                                       VARIANT* result,
02208                                       EXCEPINFO* pExcepInfo,
02209                                       UINT* puArgErr)
02210 {
02211     IDispatch *dispatch;
02212     HRESULT hr;
02213 
02214     if (!(flags & DISPATCH_PROPERTYGET))
02215         return DISP_E_MEMBERNOTFOUND;
02216 
02217     hr = create_list(NULL, &dispatch);
02218     if (FAILED(hr))
02219         return hr;
02220 
02221     V_VT(result) = VT_DISPATCH;
02222     V_DISPATCH(result) = dispatch;
02223 
02224     return hr;
02225 }
02226 
02227 static HRESULT InstallerImpl_RelatedProducts(WORD flags,
02228                                              DISPPARAMS* pDispParams,
02229                                              VARIANT* result,
02230                                              EXCEPINFO* pExcepInfo,
02231                                              UINT* puArgErr)
02232 {
02233     IDispatch* dispatch;
02234     VARIANTARG related;
02235     HRESULT hr;
02236 
02237     if (!(flags & DISPATCH_PROPERTYGET))
02238         return DISP_E_MEMBERNOTFOUND;
02239 
02240     VariantInit(&related);
02241     hr = DispGetParam(pDispParams, 0, VT_BSTR, &related, puArgErr);
02242     if (FAILED(hr))
02243         return hr;
02244 
02245     hr = create_list(V_BSTR(&related), &dispatch);
02246     VariantClear(&related);
02247 
02248     V_VT(result) = VT_DISPATCH;
02249     V_DISPATCH(result) = dispatch;
02250 
02251     return hr;
02252 }
02253 
02254 static HRESULT InstallerImpl_Invoke(
02255         AutomationObject* This,
02256         DISPID dispIdMember,
02257         REFIID riid,
02258         LCID lcid,
02259         WORD wFlags,
02260         DISPPARAMS* pDispParams,
02261         VARIANT* pVarResult,
02262         EXCEPINFO* pExcepInfo,
02263         UINT* puArgErr)
02264 {
02265     switch (dispIdMember)
02266     {
02267         case DISPID_INSTALLER_CREATERECORD:
02268             return InstallerImpl_CreateRecord(wFlags, pDispParams,
02269                                               pVarResult, pExcepInfo, puArgErr);
02270 
02271         case DISPID_INSTALLER_OPENPACKAGE:
02272             return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
02273                                              pVarResult, pExcepInfo, puArgErr);
02274 
02275         case DISPID_INSTALLER_OPENPRODUCT:
02276             return InstallerImpl_OpenProduct(wFlags, pDispParams,
02277                                              pVarResult, pExcepInfo, puArgErr);
02278 
02279         case DISPID_INSTALLER_OPENDATABASE:
02280             return InstallerImpl_OpenDatabase(wFlags, pDispParams,
02281                                               pVarResult, pExcepInfo, puArgErr);
02282 
02283         case DISPID_INSTALLER_SUMMARYINFORMATION:
02284             return InstallerImpl_SummaryInformation(wFlags, pDispParams,
02285                                                     pVarResult, pExcepInfo,
02286                                                     puArgErr);
02287 
02288         case DISPID_INSTALLER_UILEVEL:
02289             return InstallerImpl_UILevel(wFlags, pDispParams,
02290                                          pVarResult, pExcepInfo, puArgErr);
02291 
02292         case DISPID_INSTALLER_ENABLELOG:
02293             return InstallerImpl_EnableLog(wFlags, pDispParams,
02294                                            pVarResult, pExcepInfo, puArgErr);
02295 
02296         case DISPID_INSTALLER_INSTALLPRODUCT:
02297             return InstallerImpl_InstallProduct(wFlags, pDispParams,
02298                                                 pVarResult, pExcepInfo,
02299                                                 puArgErr);
02300 
02301         case DISPID_INSTALLER_VERSION:
02302             return InstallerImpl_Version(wFlags, pVarResult,
02303                                          pExcepInfo, puArgErr);
02304 
02305         case DISPID_INSTALLER_LASTERRORRECORD:
02306             return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
02307                                                  pVarResult, pExcepInfo,
02308                                                  puArgErr);
02309 
02310         case DISPID_INSTALLER_REGISTRYVALUE:
02311             return InstallerImpl_RegistryValue(wFlags, pDispParams,
02312                                                pVarResult, pExcepInfo,
02313                                                puArgErr);
02314 
02315         case DISPID_INSTALLER_ENVIRONMENT:
02316             return InstallerImpl_Environment(wFlags, pDispParams,
02317                                              pVarResult, pExcepInfo, puArgErr);
02318 
02319         case DISPID_INSTALLER_FILEATTRIBUTES:
02320             return InstallerImpl_FileAttributes(wFlags, pDispParams,
02321                                                 pVarResult, pExcepInfo,
02322                                                 puArgErr);
02323 
02324         case DISPID_INSTALLER_FILESIZE:
02325             return InstallerImpl_FileSize(wFlags, pDispParams,
02326                                           pVarResult, pExcepInfo, puArgErr);
02327 
02328         case DISPID_INSTALLER_FILEVERSION:
02329             return InstallerImpl_FileVersion(wFlags, pDispParams,
02330                                              pVarResult, pExcepInfo, puArgErr);
02331 
02332         case DISPID_INSTALLER_PRODUCTSTATE:
02333             return InstallerImpl_ProductState(wFlags, pDispParams,
02334                                               pVarResult, pExcepInfo, puArgErr);
02335 
02336         case DISPID_INSTALLER_PRODUCTINFO:
02337             return InstallerImpl_ProductInfo(wFlags, pDispParams,
02338                                              pVarResult, pExcepInfo, puArgErr);
02339 
02340         case DISPID_INSTALLER_PRODUCTS:
02341             return InstallerImpl_Products(wFlags, pDispParams,
02342                                           pVarResult, pExcepInfo, puArgErr);
02343 
02344         case DISPID_INSTALLER_RELATEDPRODUCTS:
02345             return InstallerImpl_RelatedProducts(wFlags, pDispParams,
02346                                                  pVarResult, pExcepInfo,
02347                                                  puArgErr);
02348 
02349         default:
02350             return DISP_E_MEMBERNOTFOUND;
02351     }
02352 }
02353 
02354 HRESULT create_msiserver(IUnknown *outer, void **ppObj)
02355 {
02356     AutomationObject *installer;
02357     HRESULT hr;
02358 
02359     TRACE("(%p %p)\n", outer, ppObj);
02360 
02361     if (outer)
02362         return CLASS_E_NOAGGREGATION;
02363 
02364     installer = msi_alloc(sizeof(AutomationObject));
02365     if (!installer) return E_OUTOFMEMORY;
02366 
02367     hr = init_automation_object(installer, 0, &DIID_Installer, InstallerImpl_Invoke, NULL);
02368     if (hr != S_OK)
02369     {
02370         msi_free(installer);
02371         return hr;
02372     }
02373 
02374     *ppObj = &installer->IDispatch_iface;
02375 
02376     return hr;
02377 }
02378 
02379 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp)
02380 {
02381     SessionObject *session;
02382     HRESULT hr;
02383 
02384     session = msi_alloc(sizeof(SessionObject));
02385     if (!session) return E_OUTOFMEMORY;
02386 
02387     hr = init_automation_object(&session->autoobj, msiHandle, &DIID_Session, SessionImpl_Invoke, NULL);
02388     if (hr != S_OK)
02389     {
02390         msi_free(session);
02391         return hr;
02392     }
02393 
02394     session->installer = installer;
02395     *disp = &session->autoobj.IDispatch_iface;
02396 
02397     return hr;
02398 }
02399 
02400 static HRESULT create_database(MSIHANDLE msiHandle, IDispatch **dispatch)
02401 {
02402     AutomationObject *database;
02403     HRESULT hr;
02404 
02405     TRACE("(%d %p)\n", msiHandle, dispatch);
02406 
02407     database = msi_alloc(sizeof(AutomationObject));
02408     if (!database) return E_OUTOFMEMORY;
02409 
02410     hr = init_automation_object(database, msiHandle, &DIID_Database, DatabaseImpl_Invoke, NULL);
02411     if (hr != S_OK)
02412     {
02413         msi_free(database);
02414         return hr;
02415     }
02416 
02417     *dispatch = &database->IDispatch_iface;
02418 
02419     return hr;
02420 }
02421 
02422 static HRESULT create_view(MSIHANDLE msiHandle, IDispatch **dispatch)
02423 {
02424     AutomationObject *view;
02425     HRESULT hr;
02426 
02427     TRACE("(%d %p)\n", msiHandle, dispatch);
02428 
02429     view = msi_alloc(sizeof(AutomationObject));
02430     if (!view) return E_OUTOFMEMORY;
02431 
02432     hr = init_automation_object(view, msiHandle, &DIID_View, ViewImpl_Invoke, NULL);
02433     if (hr != S_OK)
02434     {
02435         msi_free(view);
02436         return hr;
02437     }
02438 
02439     *dispatch = &view->IDispatch_iface;
02440 
02441     return hr;
02442 }
02443 
02444 static HRESULT create_summaryinfo(MSIHANDLE msiHandle, IDispatch **disp)
02445 {
02446     AutomationObject *info;
02447     HRESULT hr;
02448 
02449     info = msi_alloc(sizeof(*info));
02450     if (!info) return E_OUTOFMEMORY;
02451 
02452     hr = init_automation_object(info, msiHandle, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL);
02453     if (hr != S_OK)
02454     {
02455         msi_free(info);
02456         return hr;
02457     }
02458 
02459     *disp = &info->IDispatch_iface;
02460 
02461     return hr;
02462 }

Generated on Sun May 27 2012 04:25:12 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.