Commit 8a012ff4 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

msi: Implement list on top of general object.

parent 07058e00
...@@ -74,30 +74,24 @@ struct AutomationObject { ...@@ -74,30 +74,24 @@ struct AutomationObject {
autoFreeFunc funcFree; autoFreeFunc funcFree;
}; };
static HRESULT create_list_enumerator(IUnknown*, void**, AutomationObject*, ULONG); typedef struct {
AutomationObject autoobj;
int count;
VARIANT *data;
} ListObject;
/* static HRESULT create_list_enumerator(ListObject*, void**);
* ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
*/
/* ListEnumerator - IEnumVARIANT implementation for MSI automation lists */
typedef struct { typedef struct {
IEnumVARIANT IEnumVARIANT_iface; IEnumVARIANT IEnumVARIANT_iface;
LONG ref; LONG ref;
/* Current position and pointer to AutomationObject that stores actual data */ /* Current position and pointer to AutomationObject that stores actual data */
ULONG ulPos; ULONG pos;
AutomationObject *pObj; ListObject *list;
} ListEnumerator; } ListEnumerator;
/*
* Structures for additional data required by specific automation objects
*/
typedef struct {
ULONG ulCount;
VARIANT *pVars;
} ListData;
typedef struct { typedef struct {
AutomationObject autoobj; AutomationObject autoobj;
IDispatch *installer; IDispatch *installer;
...@@ -144,16 +138,7 @@ HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID ...@@ -144,16 +138,7 @@ HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID
return S_OK; return S_OK;
} }
/* Macro to get pointer to private object data */ /* AutomationObject methods */
static inline void *private_data( AutomationObject *This )
{
return This + 1;
}
/*
* AutomationObject methods
*/
static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject) static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
{ {
AutomationObject *This = impl_from_IDispatch(iface); AutomationObject *This = impl_from_IDispatch(iface);
...@@ -479,17 +464,17 @@ static const IProvideMultipleClassInfoVtbl ProvideMultipleClassInfoVtbl = ...@@ -479,17 +464,17 @@ static const IProvideMultipleClassInfoVtbl ProvideMultipleClassInfoVtbl =
/* Create the automation object, placing the result in the pointer ppObj. The automation object is created /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
* with the appropriate clsid and invocation function. */ * with the appropriate clsid and invocation function. */
static HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, void **ppObj, REFIID clsid, static HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, void **ppObj, REFIID clsid,
autoInvokeFunc invokeFunc, autoFreeFunc freeFunc, SIZE_T sizetPrivateData) autoInvokeFunc invokeFunc, autoFreeFunc freeFunc)
{ {
AutomationObject *object; AutomationObject *object;
HRESULT hr; HRESULT hr;
TRACE("(%d,%p,%p,%s,%p,%p,%ld)\n", msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), invokeFunc, freeFunc, sizetPrivateData); TRACE("(%d,%p,%p,%s,%p,%p)\n", msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), invokeFunc, freeFunc);
if( pUnkOuter ) if( pUnkOuter )
return CLASS_E_NOAGGREGATION; return CLASS_E_NOAGGREGATION;
object = msi_alloc_zero( sizeof(AutomationObject) + sizetPrivateData ); object = msi_alloc_zero(sizeof(AutomationObject));
object->IDispatch_iface.lpVtbl = &AutomationObjectVtbl; object->IDispatch_iface.lpVtbl = &AutomationObjectVtbl;
object->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl; object->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl;
...@@ -553,15 +538,18 @@ static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID ...@@ -553,15 +538,18 @@ static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID
*ppvObject = 0; *ppvObject = 0;
if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT)) if (IsEqualGUID(riid, &IID_IUnknown) ||
*ppvObject = This; IsEqualGUID(riid, &IID_IEnumVARIANT))
{
*ppvObject = &This->IEnumVARIANT_iface;
}
else else
{ {
TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid)); TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
return E_NOINTERFACE; return E_NOINTERFACE;
} }
IClassFactory_AddRef(iface); IEnumVARIANT_AddRef(iface);
return S_OK; return S_OK;
} }
...@@ -583,7 +571,7 @@ static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface) ...@@ -583,7 +571,7 @@ static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
if (!ref) if (!ref)
{ {
if (This->pObj) IDispatch_Release(&This->pObj->IDispatch_iface); if (This->list) IDispatch_Release(&This->list->autoobj.IDispatch_iface);
msi_free(This); msi_free(This);
} }
...@@ -591,29 +579,26 @@ static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface) ...@@ -591,29 +579,26 @@ static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
} }
static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar, static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar,
ULONG* pCeltFetched) ULONG* fetched)
{ {
ListEnumerator *This = impl_from_IEnumVARIANT(iface); ListEnumerator *This = impl_from_IEnumVARIANT(iface);
ListData *data = private_data(This->pObj); ULONG i, local;
ULONG idx, local;
TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched); TRACE("(%p, %uld, %p, %p)\n", iface, celt, rgVar, fetched);
if (pCeltFetched != NULL) if (fetched) *fetched = 0;
*pCeltFetched = 0;
if (rgVar == NULL) if (!rgVar)
return S_FALSE; return S_FALSE;
for (local = 0; local < celt; local++) for (local = 0; local < celt; local++)
VariantInit(&rgVar[local]); VariantInit(&rgVar[local]);
for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++) for (i = This->pos, local = 0; i < This->list->count && local < celt; i++, local++)
VariantCopy(&rgVar[local], &data->pVars[idx]); VariantCopy(&rgVar[local], &This->list->data[i]);
if (pCeltFetched != NULL) if (fetched) *fetched = local;
*pCeltFetched = local; This->pos = i;
This->ulPos = idx;
return (local < celt) ? S_FALSE : S_OK; return (local < celt) ? S_FALSE : S_OK;
} }
...@@ -621,16 +606,16 @@ static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIA ...@@ -621,16 +606,16 @@ static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIA
static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt) static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
{ {
ListEnumerator *This = impl_from_IEnumVARIANT(iface); ListEnumerator *This = impl_from_IEnumVARIANT(iface);
ListData *data = private_data(This->pObj);
TRACE("(%p,%uld)\n", iface, celt); TRACE("(%p,%uld)\n", iface, celt);
This->ulPos += celt; This->pos += celt;
if (This->ulPos >= data->ulCount) if (This->pos >= This->list->count)
{ {
This->ulPos = data->ulCount; This->pos = This->list->count;
return S_FALSE; return S_FALSE;
} }
return S_OK; return S_OK;
} }
...@@ -640,7 +625,7 @@ static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface) ...@@ -640,7 +625,7 @@ static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
TRACE("(%p)\n", iface); TRACE("(%p)\n", iface);
This->ulPos = 0; This->pos = 0;
return S_OK; return S_OK;
} }
...@@ -655,7 +640,7 @@ static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **p ...@@ -655,7 +640,7 @@ static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **p
return S_FALSE; return S_FALSE;
*ppEnum = NULL; *ppEnum = NULL;
hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0); hr = create_list_enumerator(This->list, (LPVOID *)ppEnum);
if (FAILED(hr)) if (FAILED(hr))
{ {
if (*ppEnum) if (*ppEnum)
...@@ -678,25 +663,22 @@ static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl = ...@@ -678,25 +663,22 @@ static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
}; };
/* Create a list enumerator, placing the result in the pointer ppObj. */ /* Create a list enumerator, placing the result in the pointer ppObj. */
static HRESULT create_list_enumerator(IUnknown *outer, void **ppObj, AutomationObject *aut_obj, ULONG pos) static HRESULT create_list_enumerator(ListObject *list, void **ppObj)
{ {
ListEnumerator *object; ListEnumerator *object;
TRACE("(%p, %p, %p, %uld)\n", outer, ppObj, aut_obj, pos); TRACE("(%p, %p)\n", list, ppObj);
if( outer )
return CLASS_E_NOAGGREGATION;
object = msi_alloc( sizeof(ListEnumerator) ); object = msi_alloc(sizeof(ListEnumerator));
/* Set all the VTable references */ /* Set all the VTable references */
object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl; object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
object->ref = 1; object->ref = 1;
/* Store data that was passed */ /* Store data that was passed */
object->ulPos = pos; object->pos = 0;
object->pObj = aut_obj; object->list = list;
if (aut_obj) IDispatch_AddRef(&aut_obj->IDispatch_iface); if (list) IDispatch_AddRef(&list->autoobj.IDispatch_iface);
*ppObj = object; *ppObj = object;
return S_OK; return S_OK;
...@@ -989,19 +971,16 @@ static HRESULT ListImpl_Invoke( ...@@ -989,19 +971,16 @@ static HRESULT ListImpl_Invoke(
EXCEPINFO* pExcepInfo, EXCEPINFO* pExcepInfo,
UINT* puArgErr) UINT* puArgErr)
{ {
ListData *data = private_data(This); ListObject *list = (ListObject*)This;
HRESULT hr;
VARIANTARG varg0;
IUnknown *pUnk = NULL; IUnknown *pUnk = NULL;
HRESULT hr;
VariantInit(&varg0);
switch (dispIdMember) switch (dispIdMember)
{ {
case DISPID_LIST__NEWENUM: case DISPID_LIST__NEWENUM:
if (wFlags & DISPATCH_METHOD) { if (wFlags & DISPATCH_METHOD) {
V_VT(pVarResult) = VT_UNKNOWN; V_VT(pVarResult) = VT_UNKNOWN;
if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0))) if (SUCCEEDED(hr = create_list_enumerator(list, (LPVOID *)&pUnk)))
V_UNKNOWN(pVarResult) = pUnk; V_UNKNOWN(pVarResult) = pUnk;
else else
ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr); ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
...@@ -1011,11 +990,14 @@ static HRESULT ListImpl_Invoke( ...@@ -1011,11 +990,14 @@ static HRESULT ListImpl_Invoke(
case DISPID_LIST_ITEM: case DISPID_LIST_ITEM:
if (wFlags & DISPATCH_PROPERTYGET) { if (wFlags & DISPATCH_PROPERTYGET) {
hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); VARIANTARG index;
VariantInit(&index);
hr = DispGetParam(pDispParams, 0, VT_I4, &index, puArgErr);
if (FAILED(hr)) return hr; if (FAILED(hr)) return hr;
if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount) if (V_I4(&index) < 0 || V_I4(&index) >= list->count)
return DISP_E_BADINDEX; return DISP_E_BADINDEX;
VariantCopy(pVarResult, &data->pVars[V_I4(&varg0)]); VariantCopy(pVarResult, &list->data[V_I4(&index)]);
} }
else return DISP_E_MEMBERNOTFOUND; else return DISP_E_MEMBERNOTFOUND;
break; break;
...@@ -1023,7 +1005,7 @@ static HRESULT ListImpl_Invoke( ...@@ -1023,7 +1005,7 @@ static HRESULT ListImpl_Invoke(
case DISPID_LIST_COUNT: case DISPID_LIST_COUNT:
if (wFlags & DISPATCH_PROPERTYGET) { if (wFlags & DISPATCH_PROPERTYGET) {
V_VT(pVarResult) = VT_I4; V_VT(pVarResult) = VT_I4;
V_I4(pVarResult) = data->ulCount; V_I4(pVarResult) = list->count;
} }
else return DISP_E_MEMBERNOTFOUND; else return DISP_E_MEMBERNOTFOUND;
break; break;
...@@ -1032,19 +1014,97 @@ static HRESULT ListImpl_Invoke( ...@@ -1032,19 +1014,97 @@ static HRESULT ListImpl_Invoke(
return DISP_E_MEMBERNOTFOUND; return DISP_E_MEMBERNOTFOUND;
} }
VariantClear(&varg0);
return S_OK; return S_OK;
} }
static void ListImpl_Free(AutomationObject *This) static void ListImpl_Free(AutomationObject *This)
{ {
ListData *data = private_data(This); ListObject *list = (ListObject*)This;
ULONG idx; int i;
for (idx=0; idx<data->ulCount; idx++) for (i = 0; i < list->count; i++)
VariantClear(&data->pVars[idx]); VariantClear(&list->data[i]);
msi_free(data->pVars); msi_free(list->data);
}
static HRESULT get_products_count(const WCHAR *product, int *len)
{
int i = 0;
while (1)
{
WCHAR dataW[GUID_SIZE];
UINT ret;
/* all or related only */
if (product)
ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
else
ret = MsiEnumProductsW(i, dataW);
if (ret == ERROR_NO_MORE_ITEMS) break;
if (ret != ERROR_SUCCESS)
return DISP_E_EXCEPTION;
i++;
}
*len = i;
return S_OK;
}
static HRESULT create_list(const WCHAR *product, IDispatch **dispatch)
{
ListObject *list;
HRESULT hr;
int i;
list = msi_alloc_zero(sizeof(ListObject));
if (!list) return E_OUTOFMEMORY;
hr = init_automation_object(&list->autoobj, 0, &DIID_StringList, ListImpl_Invoke, ListImpl_Free);
if (hr != S_OK)
{
msi_free(list);
return hr;
}
*dispatch = &list->autoobj.IDispatch_iface;
hr = get_products_count(product, &list->count);
if (hr != S_OK)
{
IDispatch_Release(*dispatch);
return hr;
}
list->data = msi_alloc(list->count*sizeof(VARIANT));
if (!list->data)
{
IDispatch_Release(*dispatch);
return E_OUTOFMEMORY;
}
for (i = 0; i < list->count; i++)
{
WCHAR dataW[GUID_SIZE];
UINT ret;
/* all or related only */
if (product)
ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
else
ret = MsiEnumProductsW(i, dataW);
if (ret == ERROR_NO_MORE_ITEMS) break;
V_VT(&list->data[i]) = VT_BSTR;
V_BSTR(&list->data[i]) = SysAllocString(dataW);
}
return S_OK;
} }
static HRESULT ViewImpl_Invoke( static HRESULT ViewImpl_Invoke(
...@@ -1087,7 +1147,7 @@ static HRESULT ViewImpl_Invoke( ...@@ -1087,7 +1147,7 @@ static HRESULT ViewImpl_Invoke(
V_VT(pVarResult) = VT_DISPATCH; V_VT(pVarResult) = VT_DISPATCH;
if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS) if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
{ {
if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0))) if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL)))
V_DISPATCH(pVarResult) = pDispatch; V_DISPATCH(pVarResult) = pDispatch;
else else
ERR("Failed to create Record object, hresult 0x%08x\n", hr); ERR("Failed to create Record object, hresult 0x%08x\n", hr);
...@@ -1186,7 +1246,7 @@ static HRESULT DatabaseImpl_Invoke( ...@@ -1186,7 +1246,7 @@ static HRESULT DatabaseImpl_Invoke(
V_VT(pVarResult) = VT_DISPATCH; V_VT(pVarResult) = VT_DISPATCH;
if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS) if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
{ {
hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0); hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
V_DISPATCH(pVarResult) = pDispatch; V_DISPATCH(pVarResult) = pDispatch;
else else
...@@ -1209,7 +1269,7 @@ static HRESULT DatabaseImpl_Invoke( ...@@ -1209,7 +1269,7 @@ static HRESULT DatabaseImpl_Invoke(
V_VT(pVarResult) = VT_DISPATCH; V_VT(pVarResult) = VT_DISPATCH;
if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS) if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
{ {
if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0))) if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL)))
V_DISPATCH(pVarResult) = pDispatch; V_DISPATCH(pVarResult) = pDispatch;
else else
ERR("Failed to create View object, hresult 0x%08x\n", hr); ERR("Failed to create View object, hresult 0x%08x\n", hr);
...@@ -1605,7 +1665,7 @@ static HRESULT InstallerImpl_CreateRecord(WORD wFlags, ...@@ -1605,7 +1665,7 @@ static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
return DISP_E_EXCEPTION; return DISP_E_EXCEPTION;
hr = create_automation_object(hrec, NULL, (LPVOID*)&dispatch, hr = create_automation_object(hrec, NULL, (LPVOID*)&dispatch,
&DIID_Record, RecordImpl_Invoke, NULL, 0); &DIID_Record, RecordImpl_Invoke, NULL);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
V_DISPATCH(pVarResult) = dispatch; V_DISPATCH(pVarResult) = dispatch;
...@@ -2178,157 +2238,52 @@ done: ...@@ -2178,157 +2238,52 @@ done:
return hr; return hr;
} }
static void cleanup_products(IDispatch* dispatch, ULONG count) static HRESULT InstallerImpl_Products(WORD flags,
{
UINT i;
ListData* ldata = private_data((AutomationObject *)dispatch);
for (i = 0; i < count - 1; i++)
VariantClear(&ldata->pVars[i]);
ldata->ulCount = 0;
msi_free(ldata->pVars);
IDispatch_Release(dispatch);
}
static HRESULT InstallerImpl_Products(WORD wFlags,
DISPPARAMS* pDispParams, DISPPARAMS* pDispParams,
VARIANT* pVarResult, VARIANT* result,
EXCEPINFO* pExcepInfo, EXCEPINFO* pExcepInfo,
UINT* puArgErr) UINT* puArgErr)
{ {
UINT ret;
HRESULT hr;
ULONG idx = 0;
ListData *ldata;
IDispatch *dispatch; IDispatch *dispatch;
WCHAR product[GUID_SIZE]; HRESULT hr;
if (!(wFlags & DISPATCH_PROPERTYGET)) if (!(flags & DISPATCH_PROPERTYGET))
return DISP_E_MEMBERNOTFOUND; return DISP_E_MEMBERNOTFOUND;
/* Find number of products. */ hr = create_list(NULL, &dispatch);
while ((ret = MsiEnumProductsW(idx, product)) == ERROR_SUCCESS)
idx++;
if (ret != ERROR_NO_MORE_ITEMS)
return DISP_E_EXCEPTION;
V_VT(pVarResult) = VT_DISPATCH;
hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
&DIID_StringList, ListImpl_Invoke,
ListImpl_Free, sizeof(ListData));
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
V_DISPATCH(pVarResult) = dispatch; V_VT(result) = VT_DISPATCH;
V_DISPATCH(result) = dispatch;
/* Save product strings. */
ldata = private_data((AutomationObject *)dispatch);
ldata->ulCount = 0;
ldata->pVars = msi_alloc_zero(sizeof(VARIANT) * idx);
if (!ldata->pVars)
{
IDispatch_Release(dispatch);
return E_OUTOFMEMORY;
}
ldata->ulCount = idx; return hr;
for (idx = 0; idx < ldata->ulCount; idx++)
{
ret = MsiEnumProductsW(idx, product);
if (ret != ERROR_SUCCESS)
{
cleanup_products(dispatch, idx - 1);
return DISP_E_EXCEPTION;
}
VariantInit(&ldata->pVars[idx]);
V_VT(&ldata->pVars[idx]) = VT_BSTR;
V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
}
return S_OK;
} }
static HRESULT InstallerImpl_RelatedProducts(WORD wFlags, static HRESULT InstallerImpl_RelatedProducts(WORD flags,
DISPPARAMS* pDispParams, DISPPARAMS* pDispParams,
VARIANT* pVarResult, VARIANT* result,
EXCEPINFO* pExcepInfo, EXCEPINFO* pExcepInfo,
UINT* puArgErr) UINT* puArgErr)
{ {
UINT ret;
ULONG idx;
HRESULT hr;
ListData *ldata;
VARIANTARG varg0;
IDispatch* dispatch; IDispatch* dispatch;
WCHAR product[GUID_SIZE]; VARIANTARG related;
HRESULT hr;
if (!(wFlags & DISPATCH_PROPERTYGET)) if (!(flags & DISPATCH_PROPERTYGET))
return DISP_E_MEMBERNOTFOUND; return DISP_E_MEMBERNOTFOUND;
VariantInit(&varg0); VariantInit(&related);
hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); hr = DispGetParam(pDispParams, 0, VT_BSTR, &related, puArgErr);
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
/* Find number of related products. */ hr = create_list(V_BSTR(&related), &dispatch);
idx = 0; VariantClear(&related);
do
{
ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
if (ret == ERROR_SUCCESS)
idx++;
} while (ret == ERROR_SUCCESS);
if (ret != ERROR_NO_MORE_ITEMS)
{
hr = DISP_E_EXCEPTION;
goto done;
}
V_VT(pVarResult) = VT_DISPATCH;
hr = create_automation_object(0, NULL, (LPVOID*)&dispatch, V_VT(result) = VT_DISPATCH;
&DIID_StringList, ListImpl_Invoke, V_DISPATCH(result) = dispatch;
ListImpl_Free, sizeof(ListData));
if (FAILED(hr))
goto done;
V_DISPATCH(pVarResult) = dispatch;
/* Save product strings. */
ldata = private_data((AutomationObject *)dispatch);
ldata->pVars = msi_alloc(sizeof(VARIANT) * idx);
if (!ldata->pVars)
{
IDispatch_Release(dispatch);
hr = E_OUTOFMEMORY;
goto done;
}
ldata->ulCount = idx;
for (idx = 0; idx < ldata->ulCount; idx++)
{
ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
if (ret != ERROR_SUCCESS)
{
cleanup_products(dispatch, idx - 1);
hr = DISP_E_EXCEPTION;
goto done;
}
VariantInit(&ldata->pVars[idx]);
V_VT(&ldata->pVars[idx]) = VT_BSTR;
V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
}
hr = S_OK;
done:
VariantClear(&varg0);
return hr; return hr;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment