From 01460f6753476c4d5b66d3b2a56a25907b19b0c8 Mon Sep 17 00:00:00 2001 From: Misha Koshelev Date: Fri, 18 May 2007 11:23:19 -0500 Subject: [PATCH] msi: automation: Implement StringList::_NewEnum. --- dlls/msi/automation.c | 203 ++++++++++++++++++++++++++++++++++- dlls/msi/msiserver.idl | 2 + dlls/msi/msiserver_dispids.h | 1 + dlls/msi/tests/automation.c | 13 +-- 4 files changed, 210 insertions(+), 9 deletions(-) diff --git a/dlls/msi/automation.c b/dlls/msi/automation.c index 98ec16644c3..63fea99c1a3 100644 --- a/dlls/msi/automation.c +++ b/dlls/msi/automation.c @@ -79,6 +79,24 @@ interface AutomationObject { void (STDMETHODCALLTYPE *funcFree)(AutomationObject* This); }; +/* + * ListEnumerator - IEnumVARIANT implementation for MSI automation lists. + */ + +typedef interface ListEnumerator ListEnumerator; + +interface ListEnumerator { + /* VTables */ + const IEnumVARIANTVtbl *lpVtbl; + + /* Object reference count */ + LONG ref; + + /* Current position and pointer to AutomationObject that stores actual data */ + ULONG ulPos; + AutomationObject *pObj; +}; + /* * Structures for additional data required by specific automation objects */ @@ -96,6 +114,7 @@ typedef struct { /* VTables */ static const struct IDispatchVtbl AutomationObject_Vtbl; static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl; +static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl; /* Load type info so we don't have to process GetIDsOfNames */ HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid) @@ -170,6 +189,31 @@ HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOI return S_OK; } +/* Create a list enumerator, placing the result in the pointer ppObj. */ +HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos) +{ + ListEnumerator *object; + + TRACE("(%p,%p,%p,%uld)\n", pUnkOuter, ppObj, pObj, ulPos); + + if( pUnkOuter ) + return CLASS_E_NOAGGREGATION; + + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ListEnumerator)); + + /* Set all the VTable references */ + object->lpVtbl = &ListEnumerator_Vtbl; + object->ref = 1; + + /* Store data that was passed */ + object->ulPos = ulPos; + object->pObj = pObj; + if (pObj) IDispatch_AddRef((IDispatch *)pObj); + + *ppObj = object; + return S_OK; +} + /* Macros to get pointer to AutomationObject from the other VTables. */ static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface ) { @@ -511,6 +555,148 @@ static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClas AutomationObject_GetInfoOfIndex }; +/* + * ListEnumerator methods + */ + +/*** IUnknown methods ***/ +static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, void** ppvObject) +{ + ListEnumerator *This = (ListEnumerator *)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_IEnumVARIANT)) + *ppvObject = This; + else + { + TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid)); + return E_NOINTERFACE; + } + + IClassFactory_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface) +{ + ListEnumerator *This = (ListEnumerator *)iface; + + TRACE("(%p/%p)\n", iface, This); + + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface) +{ + ListEnumerator *This = (ListEnumerator *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p/%p)\n", iface, This); + + if (!ref) + { + if (This->pObj) IDispatch_Release((IDispatch *)This->pObj); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +/* IEnumVARIANT methods */ + +static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) +{ + ListEnumerator *This = (ListEnumerator *)iface; + ListData *data = (ListData *)private_data(This->pObj); + ULONG idx, local; + + TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched); + + if (pCeltFetched != NULL) + *pCeltFetched = 0; + + if (rgVar == NULL) + return S_FALSE; + + for (local = 0; local < celt; local++) + VariantInit(&rgVar[local]); + + for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++) + VariantCopy(&rgVar[local], &data->pVars[idx]); + + if (pCeltFetched != NULL) + *pCeltFetched = local; + This->ulPos = idx; + + return (local < celt) ? S_FALSE : S_OK; +} + +static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt) +{ + ListEnumerator *This = (ListEnumerator *)iface; + ListData *data = (ListData *)private_data(This->pObj); + + TRACE("(%p,%uld)\n", iface, celt); + + This->ulPos += celt; + if (This->ulPos >= data->ulCount) + { + This->ulPos = data->ulCount; + return S_FALSE; + } + return S_OK; +} + +static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface) +{ + ListEnumerator *This = (ListEnumerator *)iface; + + TRACE("(%p)\n", iface); + + This->ulPos = 0; + return S_OK; +} + +static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum) +{ + ListEnumerator *This = (ListEnumerator *)iface; + HRESULT hr; + + TRACE("(%p,%p)\n", iface, ppEnum); + + if (ppEnum == NULL) + return S_FALSE; + + *ppEnum = NULL; + hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0); + if (FAILED(hr)) + { + if (*ppEnum) + IUnknown_Release(*ppEnum); + return hr; + } + + IUnknown_AddRef(*ppEnum); + return S_OK; +} + +static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl = +{ + ListEnumerator_QueryInterface, + ListEnumerator_AddRef, + ListEnumerator_Release, + ListEnumerator_Next, + ListEnumerator_Skip, + ListEnumerator_Reset, + ListEnumerator_Clone +}; + /* * Individual Object Invocation Functions */ @@ -649,13 +835,28 @@ static HRESULT WINAPI ListImpl_Invoke( ListData *data = (ListData *)private_data(This); HRESULT hr; VARIANTARG varg0; + IUnknown *pUnk = NULL; VariantInit(&varg0); switch (dispIdMember) { + case DISPID_LIST__NEWENUM: + if (wFlags & DISPATCH_METHOD) { + V_VT(pVarResult) = VT_UNKNOWN; + if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0))) + { + IUnknown_AddRef(pUnk); + V_UNKNOWN(pVarResult) = pUnk; + } + else + ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr); + } + else return DISP_E_MEMBERNOTFOUND; + break; + case DISPID_LIST_ITEM: - if (wFlags & DISPATCH_PROPERTYGET) { + if (wFlags & DISPATCH_PROPERTYGET) { hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); if (FAILED(hr)) return hr; if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount) diff --git a/dlls/msi/msiserver.idl b/dlls/msi/msiserver.idl index 485334c829a..360e4f140ae 100644 --- a/dlls/msi/msiserver.idl +++ b/dlls/msi/msiserver.idl @@ -114,6 +114,8 @@ library WindowsInstaller { properties: methods: + [id(DISPID_LIST__NEWENUM)] + IUnknown _NewEnum(); [id(DISPID_LIST_ITEM), propget] BSTR Item(long Index); [id(DISPID_LIST_COUNT), propget] diff --git a/dlls/msi/msiserver_dispids.h b/dlls/msi/msiserver_dispids.h index 5ef21c85161..694090e1024 100644 --- a/dlls/msi/msiserver_dispids.h +++ b/dlls/msi/msiserver_dispids.h @@ -29,6 +29,7 @@ #define DISPID_RECORD_STRINGDATA 1 #define DISPID_RECORD_INTEGERDATA 2 +#define DISPID_LIST__NEWENUM -4 #define DISPID_LIST_ITEM 0 #define DISPID_LIST_COUNT 1 diff --git a/dlls/msi/tests/automation.c b/dlls/msi/tests/automation.c index 82fe05efd62..9bd7d03517b 100644 --- a/dlls/msi/tests/automation.c +++ b/dlls/msi/tests/automation.c @@ -1910,15 +1910,12 @@ static void test_Installer(void) ULONG celt; /* StringList::_NewEnum */ - todo_wine + hr = StringList__NewEnum(pStringList, &pUnk); + ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr); + if (hr == S_OK) { - hr = StringList__NewEnum(pStringList, &pUnk); - ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr); - if (hr == S_OK) - { - hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum); - ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr); - } + hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum); + ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr); } if (!pEnum) skip("IEnumVARIANT tests\n");