From 5a41c336b7c27d70ce50bdc7e930a6bf6692c7ce Mon Sep 17 00:00:00 2001 From: Misha Koshelev Date: Wed, 28 Feb 2007 12:10:18 -0600 Subject: msi: Add partial, expandable OLE automation support. --- dlls/msi/Makefile.in | 3 dlls/msi/automation.c | 826 +++++++++++++++++++++++++++++++++++++++++++++++++ dlls/msi/msipriv.h | 4 3 files changed, 833 insertions(+), 0 deletions(-) diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in index 5fb0941..3418fb5 100644 --- a/dlls/msi/Makefile.in +++ b/dlls/msi/Makefile.in @@ -12,6 +12,7 @@ C_SRCS = \ action.c \ alter.c \ appsearch.c \ + automation.c \ classes.c \ create.c \ custom.c \ @@ -47,6 +48,8 @@ C_SRCS = \ upgrade.c \ where.c +IDL_H_SRCS = msiserver.idl +IDL_I_SRCS = msiserver.idl IDL_TLB_SRCS = msiserver.idl BISON_SRCS = \ diff --git a/dlls/msi/automation.c b/dlls/msi/automation.c new file mode 100644 index 0000000..cfb2cf1 --- /dev/null +++ b/dlls/msi/automation.c @@ -0,0 +1,826 @@ +/* + * Implementation of OLE Automation for Microsoft Installer (msi.dll) + * + * Copyright 2007 Misha Koshelev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winuser.h" +#include "msidefs.h" +#include "msipriv.h" +#include "activscp.h" +#include "oleauto.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "msiserver.h" +#include "msiserver_dispids.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +/* FIXME: I don't know how big this should be */ +#define MAX_MSI_STRING 1000 + +/* + * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function + * called from AutomationObject::Invoke, and pass this function to create_automation_object. + */ + +typedef interface AutomationObject AutomationObject; + +interface AutomationObject { + /* + * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo + */ + const IDispatchVtbl *lpVtbl; + const IProvideClassInfoVtbl *lpvtblIProvideClassInfo; + const IProvideClassInfo2Vtbl *lpvtblIProvideClassInfo2; + const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo; + + /* Object reference count */ + LONG ref; + + /* Clsid for this class and it's appropriate ITypeInfo object */ + LPCLSID clsid; + ITypeInfo *iTypeInfo; + + /* The MSI handle of the current object */ + MSIHANDLE msiHandle; + + /* A function that is called from AutomationObject::Invoke, specific to this type of object. */ + HRESULT (STDMETHODCALLTYPE *funcInvoke)( + AutomationObject* This, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr); +}; + +/* VTables */ +static const struct IDispatchVtbl AutomationObject_Vtbl; +static const struct IProvideClassInfoVtbl AutomationObject_IProvideClassInfo_Vtbl; +static const struct IProvideClassInfo2Vtbl AutomationObject_IProvideClassInfo2_Vtbl; +static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl; + +/* Load type info so we don't have to process GetIDsOfNames */ +HRESULT WINAPI LoadTypeInfo(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid) +{ + HRESULT hr; + LPTYPELIB pLib = NULL; + LPTYPEINFO pInfo = NULL; + WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'}; + + TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid); + + /* Load registered type library */ + hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib); + if (FAILED(hr)) { + hr = LoadTypeLib(szMsiServer, &pLib); + if (FAILED(hr)) { + ERR("Could not load msiserver.tlb\n"); + return hr; + } + } + + /* Get type information for object */ + hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo); + ITypeLib_Release(pLib); + if (FAILED(hr)) { + ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid)); + return hr; + } + *pptinfo = pInfo; + return S_OK; +} + +/* Create the automation object, placing the result in the pointer ppObj. The automation object is created + * with the appropriate clsid and invocation function. */ +HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid, + HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*, + VARIANT*,EXCEPINFO*,UINT*)) +{ + AutomationObject *object; + HRESULT hr; + + TRACE("(%ld,%p,%p,%s,%p)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke); + + if( pUnkOuter ) + return CLASS_E_NOAGGREGATION; + + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)); + + /* Set all the VTable references */ + object->lpVtbl = &AutomationObject_Vtbl; + object->lpvtblIProvideClassInfo = &AutomationObject_IProvideClassInfo_Vtbl; + object->lpvtblIProvideClassInfo2 = &AutomationObject_IProvideClassInfo2_Vtbl; + object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl; + object->ref = 1; + + /* Store data that was passed */ + object->msiHandle = msiHandle; + object->clsid = (LPCLSID)clsid; + object->funcInvoke = funcInvoke; + + /* Load our TypeInfo so we don't have to process GetIDsOfNames */ + object->iTypeInfo = NULL; + hr = LoadTypeInfo((IDispatch *)object, &object->iTypeInfo, clsid, 0x0); + if (FAILED(hr)) { + HeapFree(GetProcessHeap(), 0, object); + return hr; + } + + *ppObj = object; + + return S_OK; +} + +/* Macros to get pointer to AutomationObject from the other VTables. */ +static inline AutomationObject *obj_from_IProvideClassInfo( IProvideClassInfo *iface ) +{ + return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideClassInfo)); +} + +static inline AutomationObject *obj_from_IProvideClassInfo2( IProvideClassInfo2 *iface ) +{ + return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideClassInfo2)); +} + +static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface ) +{ + return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo)); +} + +/* + * AutomationObject methods + */ + +/*** IUnknown methods ***/ +static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject) +{ + AutomationObject *This = (AutomationObject *)iface; + + TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject); + + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + *ppvObject = 0; + + if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid)) + *ppvObject = This; + else if (IsEqualGUID(riid, &IID_IProvideClassInfo)) + *ppvObject = (IProvideClassInfo*)&(This->lpvtblIProvideClassInfo); + else if (IsEqualGUID(riid, &IID_IProvideClassInfo2)) + *ppvObject = (IProvideClassInfo2*)&(This->lpvtblIProvideClassInfo2); + else if (IsEqualGUID(riid, &IID_IProvideMultipleClassInfo)) + *ppvObject = (IProvideMultipleClassInfo*)&(This->lpvtblIProvideMultipleClassInfo); + + if ((*ppvObject)==0) + { + TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid)); + return E_NOINTERFACE; + } + + /* + * Query Interface always increases the reference count by one when it is + * successful + */ + IClassFactory_AddRef(iface); + + return S_OK; +} + +static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface) +{ + AutomationObject *This = (AutomationObject *)iface; + + TRACE("(%p/%p)\n", iface, This); + + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI AutomationObject_Release(IDispatch* iface) +{ + AutomationObject *This = (AutomationObject *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p/%p)\n", iface, This); + + if (!ref) + { + MsiCloseHandle(This->msiHandle); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +/*** IDispatch methods ***/ +static HRESULT WINAPI AutomationObject_GetTypeInfoCount( + IDispatch* iface, + UINT* pctinfo) +{ + AutomationObject *This = (AutomationObject *)iface; + + TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo); + *pctinfo = 1; + return S_OK; +} + +static HRESULT WINAPI AutomationObject_GetTypeInfo( + IDispatch* iface, + UINT iTInfo, + LCID lcid, + ITypeInfo** ppTInfo) +{ + AutomationObject *This = (AutomationObject *)iface; + TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo); + + ITypeInfo_AddRef(This->iTypeInfo); + *ppTInfo = This->iTypeInfo; + return S_OK; +} + +static HRESULT WINAPI AutomationObject_GetIDsOfNames( + IDispatch* iface, + REFIID riid, + LPOLESTR* rgszNames, + UINT cNames, + LCID lcid, + DISPID* rgDispId) +{ + AutomationObject *This = (AutomationObject *)iface; + TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId); + + if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG; + return ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId); +} + +/* Some error checking is done here to simplify individual object function invocation */ +static HRESULT WINAPI AutomationObject_Invoke( + IDispatch* iface, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr) +{ + AutomationObject *This = (AutomationObject *)iface; + HRESULT hr; + unsigned int uArgErr; + VARIANT varResultDummy; + BSTR bstrName = NULL; + + TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + + if (!IsEqualIID(riid, &IID_NULL)) + { + ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid)); + return DISP_E_UNKNOWNNAME; + } + + if (!pDispParams) + { + ERR("NULL pDispParams not allowed\n"); + return DISP_E_PARAMNOTOPTIONAL; + } + + if (wFlags & DISPATCH_PROPERTYGET && !pVarResult) + { + ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n"); + return DISP_E_PARAMNOTOPTIONAL; + } + + /* This simplifies our individual object invocation functions */ + if (puArgErr == NULL) puArgErr = &uArgErr; + if (pVarResult == NULL) pVarResult = &varResultDummy; + + /* Assume return type is void unless determined otherwise */ + VariantInit(pVarResult); + + /* If we are tracing, we want to see the name of the member we are invoking */ + if (TRACE_ON(msi)) + { + ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL); + TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName)); + } + + hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr); + + if (hr == DISP_E_MEMBERNOTFOUND) { + if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL); + FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid)); + } + + TRACE("Returning %d, %s\n", hr, hr == S_OK ? "ok" : "not ok"); + + return hr; +} + +static const struct IDispatchVtbl AutomationObject_Vtbl = +{ + AutomationObject_QueryInterface, + AutomationObject_AddRef, + AutomationObject_Release, + AutomationObject_GetTypeInfoCount, + AutomationObject_GetTypeInfo, + AutomationObject_GetIDsOfNames, + AutomationObject_Invoke +}; + +/* + * IProvideClassInfo methods + */ + +static HRESULT WINAPI AutomationObject_IProvideClassInfo_QueryInterface( + IProvideClassInfo* iface, + REFIID riid, + VOID** ppvoid) +{ + AutomationObject *This = obj_from_IProvideClassInfo(iface); + return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid); +} + +static ULONG WINAPI AutomationObject_IProvideClassInfo_AddRef(IProvideClassInfo* iface) +{ + AutomationObject *This = obj_from_IProvideClassInfo(iface); + return AutomationObject_AddRef((IDispatch *)This); +} + +static ULONG WINAPI AutomationObject_IProvideClassInfo_Release(IProvideClassInfo* iface) +{ + AutomationObject *This = obj_from_IProvideClassInfo(iface); + return AutomationObject_Release((IDispatch *)This); +} + +static HRESULT WINAPI AutomationObject_GetClassInfo(IProvideClassInfo* iface, ITypeInfo** ppTI) +{ + AutomationObject *This = obj_from_IProvideClassInfo(iface); + + TRACE("(%p/%p)->(%p)\n", iface, This, ppTI); + return LoadTypeInfo((IDispatch *)This, ppTI, This->clsid, 0); +} + +static const IProvideClassInfoVtbl AutomationObject_IProvideClassInfo_Vtbl = +{ + AutomationObject_IProvideClassInfo_QueryInterface, + AutomationObject_IProvideClassInfo_AddRef, + AutomationObject_IProvideClassInfo_Release, + AutomationObject_GetClassInfo +}; + +/* + * IProvideClassInfo2 methods + */ + +static HRESULT WINAPI AutomationObject_IProvideClassInfo2_QueryInterface( + IProvideClassInfo2* iface, + REFIID riid, + VOID** ppvoid) +{ + AutomationObject *This = obj_from_IProvideClassInfo2(iface); + return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid); +} + +static ULONG WINAPI AutomationObject_IProvideClassInfo2_AddRef(IProvideClassInfo2* iface) +{ + AutomationObject *This = obj_from_IProvideClassInfo2(iface); + return AutomationObject_AddRef((IDispatch *)This); +} + +static ULONG WINAPI AutomationObject_IProvideClassInfo2_Release(IProvideClassInfo2* iface) +{ + AutomationObject *This = obj_from_IProvideClassInfo2(iface); + return AutomationObject_Release((IDispatch *)This); +} + +static HRESULT WINAPI AutomationObject_IProvideClassInfo2_GetClassInfo(IProvideClassInfo2* iface, ITypeInfo** ppTI) +{ + AutomationObject *This = obj_from_IProvideClassInfo2(iface); + return AutomationObject_GetClassInfo((IProvideClassInfo*)&(This->lpvtblIProvideClassInfo), ppTI); +} + +static HRESULT WINAPI AutomationObject_GetGUID(IProvideClassInfo2* iface, DWORD dwGuidKind, GUID* pGUID) +{ + AutomationObject *This = obj_from_IProvideClassInfo2(iface); + TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID)); + + if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID) + return E_INVALIDARG; + else { + *pGUID = *This->clsid; + return S_OK; + } +} + +static const IProvideClassInfo2Vtbl AutomationObject_IProvideClassInfo2_Vtbl = +{ + AutomationObject_IProvideClassInfo2_QueryInterface, + AutomationObject_IProvideClassInfo2_AddRef, + AutomationObject_IProvideClassInfo2_Release, + AutomationObject_IProvideClassInfo2_GetClassInfo, + AutomationObject_GetGUID +}; + +/* + * IProvideMultipleClassInfo methods + */ + +static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface( + IProvideMultipleClassInfo* iface, + REFIID riid, + VOID** ppvoid) +{ + AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface); + return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid); +} + +static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface) +{ + AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface); + return AutomationObject_AddRef((IDispatch *)This); +} + +static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface) +{ + AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface); + return AutomationObject_Release((IDispatch *)This); +} + +static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI) +{ + AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface); + return AutomationObject_GetClassInfo((IProvideClassInfo*)&(This->lpvtblIProvideClassInfo), ppTI); +} + +static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID) +{ + AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface); + return AutomationObject_GetGUID((IProvideClassInfo2*)&(This->lpvtblIProvideClassInfo2), dwGuidKind, pGUID); +} + +static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti) +{ + AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface); + + TRACE("(%p/%p)->(%p)\n", iface, This, pcti); + *pcti = 1; + return S_OK; +} + +static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface, + ULONG iti, + DWORD dwFlags, + ITypeInfo** pptiCoClass, + DWORD* pdwTIFlags, + ULONG* pcdispidReserved, + IID* piidPrimary, + IID* piidSource) +{ + AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface); + + TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource); + + if (iti != 0) + return E_INVALIDARG; + + if (dwFlags & MULTICLASSINFO_GETTYPEINFO) + LoadTypeInfo((IDispatch *)This, pptiCoClass, This->clsid, 0); + + if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS) + { + *pdwTIFlags = 0; + *pcdispidReserved = 0; + } + + if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){ + *piidPrimary = *This->clsid; + } + + if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){ + *piidSource = *This->clsid; + } + + return S_OK; +} + +static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl = +{ + AutomationObject_IProvideMultipleClassInfo_QueryInterface, + AutomationObject_IProvideMultipleClassInfo_AddRef, + AutomationObject_IProvideMultipleClassInfo_Release, + AutomationObject_IProvideMultipleClassInfo_GetClassInfo, + AutomationObject_IProvideMultipleClassInfo_GetGUID, + AutomationObject_GetMultiTypeInfoCount, + AutomationObject_GetInfoOfIndex +}; + +/* + * Individual Object Invocation Functions + */ + +HRESULT WINAPI RecordImpl_Invoke( + AutomationObject* This, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr) +{ + WCHAR szString[MAX_MSI_STRING]; + DWORD dwLen = MAX_MSI_STRING; + UINT ret; + VARIANTARG varg0, varg1; + HRESULT hr; + + VariantInit(&varg0); + VariantInit(&varg1); + + switch (dispIdMember) + { + case DISPID_RECORD_STRINGDATA: + if (wFlags & DISPATCH_PROPERTYGET) { + hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); + if (hr != S_OK) return hr; + V_VT(pVarResult) = VT_BSTR; + if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS) + V_BSTR(pVarResult) = SysAllocString(szString); + else + { + TRACE("MsiRecordGetString returned %d\n", ret); + V_BSTR(pVarResult) = NULL; + } + } else if (wFlags & DISPATCH_PROPERTYPUT) { + hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); + if (hr != S_OK) return hr; + hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr); + if (hr != S_OK) return hr; + if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS) + TRACE("MsiRecordSetString returned %d\n", ret); + } + break; + + default: + return DISP_E_MEMBERNOTFOUND; + } + + return S_OK; +} + +HRESULT WINAPI ViewImpl_Invoke( + AutomationObject* This, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr) +{ + MSIHANDLE msiHandle; + IDispatch *iDispatch = NULL; + UINT ret; + VARIANTARG varg0, varg1; + HRESULT hr; + + VariantInit(&varg0); + VariantInit(&varg1); + + switch (dispIdMember) + { + case DISPID_VIEW_EXECUTE: + if (wFlags & DISPATCH_METHOD) + { + hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr); + if (hr == S_OK) + MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle); + else + MsiViewExecute(This->msiHandle, 0); + } + break; + + case DISPID_VIEW_FETCH: + if (wFlags & DISPATCH_METHOD) + { + V_VT(pVarResult) = VT_DISPATCH; + if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS) + create_automation_object(msiHandle, NULL, (LPVOID)&iDispatch, &DIID_Record, RecordImpl_Invoke); + else TRACE("MsiViewFetch returned %d\n", ret); + V_DISPATCH(pVarResult) = iDispatch; + } + break; + + case DISPID_VIEW_CLOSE: + if (wFlags & DISPATCH_METHOD) + { + MsiViewClose(This->msiHandle); + } + break; + + default: + return DISP_E_MEMBERNOTFOUND; + } + + return S_OK; +} + +HRESULT WINAPI DatabaseImpl_Invoke( + AutomationObject* This, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr) +{ + MSIHANDLE msiHandle; + IDispatch *iDispatch = NULL; + UINT ret; + VARIANTARG varg0, varg1; + HRESULT hr; + + VariantInit(&varg0); + VariantInit(&varg1); + + switch (dispIdMember) + { + case DISPID_DATABASE_OPENVIEW: + if (wFlags & DISPATCH_METHOD) + { + hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); + if (hr != S_OK) return hr; + V_VT(pVarResult) = VT_DISPATCH; + if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS) + create_automation_object(msiHandle, NULL, (LPVOID)&iDispatch, &DIID_View, ViewImpl_Invoke); + else TRACE("MsiDatabaseOpenView returned %d\n", ret); + V_DISPATCH(pVarResult) = iDispatch; + } + break; + + default: + return DISP_E_MEMBERNOTFOUND; + } + + return S_OK; +} + +HRESULT WINAPI SessionImpl_Invoke( + AutomationObject* This, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr) +{ + WCHAR szString[MAX_MSI_STRING]; + DWORD dwLen = MAX_MSI_STRING; + IDispatch *iDispatch = NULL; + MSIHANDLE msiHandle; + LANGID langId; + UINT ret; + INSTALLSTATE iInstalled, iAction; + VARIANTARG varg0, varg1; + HRESULT hr; + + VariantInit(&varg0); + VariantInit(&varg1); + + switch (dispIdMember) + { + case DISPID_SESSION_PROPERTY: + if (wFlags & DISPATCH_PROPERTYGET) { + hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); + if (hr != S_OK) return hr; + V_VT(pVarResult) = VT_BSTR; + if (MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen) == ERROR_SUCCESS) + V_BSTR(pVarResult) = SysAllocString(szString); + else + V_BSTR(pVarResult) = NULL; + } else if (wFlags & DISPATCH_PROPERTYPUT) { + hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); + if (hr != S_OK) return hr; + hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr); + if (hr != S_OK) return hr; + if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS) + TRACE("MsiSetProperty returned %d\n", ret); + } + break; + + case DISPID_SESSION_LANGUAGE: + if (wFlags & DISPATCH_PROPERTYGET) { + langId = MsiGetLanguage(This->msiHandle); + V_VT(pVarResult) = VT_I4; + V_I4(pVarResult) = langId; + } + break; + + case DISPID_SESSION_MODE: + if (wFlags & DISPATCH_PROPERTYGET) { + hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); + if (hr != S_OK) return hr; + V_VT(pVarResult) = VT_BOOL; + V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0)); + } else if (wFlags & DISPATCH_PROPERTYPUT) { + hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); + if (hr != S_OK) return hr; + hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr); + if (hr != S_OK) return hr; + if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS) + TRACE("MsiSetMode returned %d\n", ret); + } + break; + + case DISPID_SESSION_DATABASE: + if (wFlags & DISPATCH_PROPERTYGET) { + V_VT(pVarResult) = VT_DISPATCH; + if ((msiHandle = MsiGetActiveDatabase(This->msiHandle))) + create_automation_object(msiHandle, NULL, (LPVOID)&iDispatch, &DIID_Database, DatabaseImpl_Invoke); + else TRACE("MsiGetActiveDatabase failed\n"); + V_DISPATCH(pVarResult) = iDispatch; + } + break; + + case DISPID_SESSION_FEATURECURRENTSTATE: + if (wFlags & DISPATCH_PROPERTYGET) { + hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); + if (hr != S_OK) return hr; + V_VT(pVarResult) = VT_I4; + if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS) + V_I4(pVarResult) = iInstalled; + else + { + TRACE("MsiGetFeatureState returned %d\n", ret); + V_I4(pVarResult) = msiInstallStateUnknown; + } + } + break; + + case DISPID_SESSION_FEATUREREQUESTSTATE: + if (wFlags & DISPATCH_PROPERTYGET) { + hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); + if (hr != S_OK) return hr; + V_VT(pVarResult) = VT_I4; + if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS) + V_I4(pVarResult) = iAction; + else + { + TRACE("MsiGetFeatureState returned %d\n", ret); + V_I4(pVarResult) = msiInstallStateUnknown; + } + } else if (wFlags & DISPATCH_PROPERTYPUT) { + hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); + if (hr != S_OK) return hr; + hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr); + if (hr != S_OK) return hr; + if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS) + TRACE("MsiSetFeatureState returned %d\n", ret); + } + break; + + default: + return DISP_E_MEMBERNOTFOUND; + } + + return S_OK; +} + +/* Wrapper around create_automation_object to create a session object. */ +HRESULT create_session(MSIHANDLE msiHandle, IDispatch **pDispatch) +{ + return create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke); +} diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 971f71e..23768c0 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -788,6 +788,10 @@ extern VOID ControlEvent_SubscribeToEven extern VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event, LPCWSTR control, LPCWSTR attribute ); +/* OLE automation */ +extern HRESULT create_session(MSIHANDLE msiHandle, IDispatch **pDispatch); +extern HRESULT WINAPI LoadTypeInfo(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid); + /* User Interface messages from the actions */ extern void ui_progress(MSIPACKAGE *, int, int, int, int); extern void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *); -- 1.4.1