msi: Add base class for OLE automation objects.

This commit is contained in:
Misha Koshelev 2007-04-30 20:53:43 -05:00 committed by Alexandre Julliard
parent d1c4588625
commit 26c16313d9
3 changed files with 476 additions and 0 deletions

2
.gitignore vendored
View File

@ -335,7 +335,9 @@ dlls/msi/instadvert.bmp
dlls/msi/instlocal.bmp
dlls/msi/libmsi.def
dlls/msi/msi.res
dlls/msi/msiserver.h
dlls/msi/msiserver.tlb
dlls/msi/msiserver_i.c
dlls/msi/sql.tab.c
dlls/msi/sql.tab.h
dlls/msi/tests/*.ok

View File

@ -12,6 +12,7 @@ C_SRCS = \
action.c \
alter.c \
appsearch.c \
automation.c \
classes.c \
create.c \
custom.c \
@ -48,6 +49,8 @@ C_SRCS = \
upgrade.c \
where.c
IDL_H_SRCS = msiserver.idl
IDL_I_SRCS = msiserver.idl
IDL_TLB_SRCS = msiserver.idl
BISON_SRCS = \

471
dlls/msi/automation.c Normal file
View File

@ -0,0 +1,471 @@
/*
* 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 <stdarg.h>
#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"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/*
* 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 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 IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
/* Load type info so we don't have to process GetIDsOfNames */
HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
{
HRESULT hr;
LPTYPELIB pLib = NULL;
LPTYPEINFO pInfo = NULL;
static const 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->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 = load_type_info((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_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 (ppvObject == NULL)
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) ||
IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
*ppvObject = &This->lpvtblIProvideMultipleClassInfo;
else
{
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);
}
/* Maximum number of allowed function parameters+1 */
#define MAX_FUNC_PARAMS 20
/* 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 (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));
}
else if (pExcepInfo &&
(hr == DISP_E_PARAMNOTFOUND ||
hr == DISP_E_EXCEPTION)) {
static const WCHAR szComma[] = { ',',0 };
static WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
WCHAR szExceptionDescription[MAX_PATH];
BSTR bstrParamNames[MAX_FUNC_PARAMS];
unsigned namesNo, i;
BOOL bFirst = TRUE;
if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
MAX_FUNC_PARAMS, &namesNo)))
{
TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
}
else
{
memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
for (i=0; i<namesNo; i++)
{
if (bFirst) bFirst = FALSE;
else {
lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
}
lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
SysFreeString(bstrParamNames[i]);
}
memset(pExcepInfo, 0, sizeof(EXCEPINFO));
pExcepInfo->wCode = 1000;
pExcepInfo->bstrSource = szExceptionSource;
pExcepInfo->bstrDescription = szExceptionDescription;
hr = DISP_E_EXCEPTION;
}
}
/* Make sure we free the return variant if it is our dummy variant */
if (pVarResult == &varResultDummy) VariantClear(pVarResult);
/* Free function name if we retrieved it */
if (bstrName) SysFreeString(bstrName);
TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "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
};
/*
* 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);
TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
}
static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
{
AutomationObject *This = obj_from_IProvideMultipleClassInfo(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 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)
load_type_info((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
};