Signed-off-by: Nikolay Sivov nsivov@codeweavers.com ---
The goal is to get rid of enumx.c, allowing clean implementation of changes in staging like
ole32-STGPROP/0003-ole32-Implement-returning-a-name-in-IEnumSTATPROPSTG.patch
dlls/ole32/stg_prop.c | 329 ++++++++++++++++++++++-------------- dlls/ole32/tests/stg_prop.c | 115 +++++++++++++ 2 files changed, 317 insertions(+), 127 deletions(-)
diff --git a/dlls/ole32/stg_prop.c b/dlls/ole32/stg_prop.c index 9e13c135ad..2e43d16b35 100644 --- a/dlls/ole32/stg_prop.c +++ b/dlls/ole32/stg_prop.c @@ -51,6 +51,7 @@ #include "winuser.h" #include "wine/asm.h" #include "wine/debug.h" +#include "wine/heap.h" #include "dictionary.h" #include "storage32.h" #include "enumx.h" @@ -142,9 +143,7 @@ static HRESULT PropertyStorage_StringCopy(LPCSTR src, LCID srcCP, LPSTR *dst, LCID targetCP);
static const IPropertyStorageVtbl IPropertyStorage_Vtbl; -static const IEnumSTATPROPSETSTGVtbl IEnumSTATPROPSETSTG_Vtbl; static const IEnumSTATPROPSTGVtbl IEnumSTATPROPSTG_Vtbl; -static HRESULT create_EnumSTATPROPSETSTG(StorageImpl *, IEnumSTATPROPSETSTG**); static HRESULT create_EnumSTATPROPSTG(PropertyStorage_impl *, IEnumSTATPROPSTG**);
/*********************************************************************** @@ -2143,6 +2142,201 @@ static HRESULT PropertyStorage_ConstructEmpty(IStream *stm, * Implementation of IPropertySetStorage */
+struct enum_stat_propset_stg +{ + IEnumSTATPROPSETSTG IEnumSTATPROPSETSTG_iface; + LONG refcount; + STATPROPSETSTG *stats; + size_t current; + size_t count; +}; + +static struct enum_stat_propset_stg *impl_from_IEnumSTATPROPSETSTG(IEnumSTATPROPSETSTG *iface) +{ + return CONTAINING_RECORD(iface, struct enum_stat_propset_stg, IEnumSTATPROPSETSTG_iface); +} + +static HRESULT WINAPI enum_stat_propset_stg_QueryInterface(IEnumSTATPROPSETSTG *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IEnumSTATPROPSETSTG) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IEnumSTATPROPSETSTG_AddRef(iface); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI enum_stat_propset_stg_AddRef(IEnumSTATPROPSETSTG *iface) +{ + struct enum_stat_propset_stg *psenum = impl_from_IEnumSTATPROPSETSTG(iface); + LONG refcount = InterlockedIncrement(&psenum->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI enum_stat_propset_stg_Release(IEnumSTATPROPSETSTG *iface) +{ + struct enum_stat_propset_stg *psenum = impl_from_IEnumSTATPROPSETSTG(iface); + LONG refcount = InterlockedDecrement(&psenum->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + heap_free(psenum->stats); + heap_free(psenum); + } + + return refcount; +} + +static HRESULT WINAPI enum_stat_propset_stg_Next(IEnumSTATPROPSETSTG *iface, ULONG celt, + STATPROPSETSTG *ret, ULONG *fetched) +{ + struct enum_stat_propset_stg *psenum = impl_from_IEnumSTATPROPSETSTG(iface); + ULONG count = 0; + + TRACE("%p, %u, %p, %p.\n", iface, celt, ret, fetched); + + if (psenum->current == ~0u) + psenum->current = 0; + + while (count < celt && psenum->current < psenum->count) + ret[count++] = psenum->stats[psenum->current++]; + + if (fetched) + *fetched = count; + + return count < celt ? S_FALSE : S_OK; +} + +static HRESULT WINAPI enum_stat_propset_stg_Skip(IEnumSTATPROPSETSTG *iface, ULONG celt) +{ + FIXME("%p, %u.\n", iface, celt); + + return S_OK; +} + +static HRESULT WINAPI enum_stat_propset_stg_Reset(IEnumSTATPROPSETSTG *iface) +{ + struct enum_stat_propset_stg *psenum = impl_from_IEnumSTATPROPSETSTG(iface); + + TRACE("%p.\n", iface); + + psenum->current = ~0u; + + return S_OK; +} + +static HRESULT WINAPI enum_stat_propset_stg_Clone(IEnumSTATPROPSETSTG *iface, IEnumSTATPROPSETSTG **ppenum) +{ + FIXME("%p, %p.\n", iface, ppenum); + + return E_NOTIMPL; +} + +static const IEnumSTATPROPSETSTGVtbl enum_stat_propset_stg_vtbl = +{ + enum_stat_propset_stg_QueryInterface, + enum_stat_propset_stg_AddRef, + enum_stat_propset_stg_Release, + enum_stat_propset_stg_Next, + enum_stat_propset_stg_Skip, + enum_stat_propset_stg_Reset, + enum_stat_propset_stg_Clone, +}; + +static HRESULT create_enum_stat_propset_stg(StorageImpl *storage, IEnumSTATPROPSETSTG **ret) +{ + IStorage *stg = &storage->base.IStorage_iface; + IEnumSTATSTG *penum = NULL; + STATSTG stat; + ULONG count; + HRESULT hr; + + struct enum_stat_propset_stg *enum_obj; + + enum_obj = heap_alloc_zero(sizeof(*enum_obj)); + if (!enum_obj) + return E_OUTOFMEMORY; + + enum_obj->IEnumSTATPROPSETSTG_iface.lpVtbl = &enum_stat_propset_stg_vtbl; + enum_obj->refcount = 1; + + /* add all the property set elements into a list */ + hr = IStorage_EnumElements(stg, 0, NULL, 0, &penum); + if (FAILED(hr)) + goto done; + + /* Allocate stats array and fill it. */ + while ((hr = IEnumSTATSTG_Next(penum, 1, &stat, &count)) == S_OK) + { + enum_obj->count++; + CoTaskMemFree(stat.pwcsName); + } + + if (FAILED(hr)) + goto done; + + enum_obj->stats = heap_alloc(enum_obj->count * sizeof(*enum_obj->stats)); + if (!enum_obj->stats) + { + hr = E_OUTOFMEMORY; + goto done; + } + enum_obj->count = 0; + + if (FAILED(hr = IEnumSTATSTG_Reset(penum))) + goto done; + + while (IEnumSTATSTG_Next(penum, 1, &stat, &count) == S_OK) + { + if (!stat.pwcsName) + continue; + + if (stat.pwcsName[0] == 5 && stat.type == STGTY_STREAM) + { + STATPROPSETSTG *ptr = &enum_obj->stats[enum_obj->count++]; + + PropStgNameToFmtId(stat.pwcsName, &ptr->fmtid); + + TRACE("adding %s - %s.\n", debugstr_w(stat.pwcsName), debugstr_guid(&ptr->fmtid)); + + ptr->mtime = stat.mtime; + ptr->atime = stat.atime; + ptr->ctime = stat.ctime; + ptr->grfFlags = stat.grfMode; + ptr->clsid = stat.clsid; + } + CoTaskMemFree(stat.pwcsName); + } + +done: + + if (penum) + IEnumSTATSTG_Release(penum); + + if (SUCCEEDED(hr)) + { + *ret = &enum_obj->IEnumSTATPROPSETSTG_iface; + } + else + { + *ret = NULL; + IEnumSTATPROPSETSTG_Release(&enum_obj->IEnumSTATPROPSETSTG_iface); + } + + return hr; +} + /************************************************************************ * IPropertySetStorage_fnQueryInterface (IUnknown) * @@ -2310,124 +2504,16 @@ static HRESULT WINAPI IPropertySetStorage_fnDelete( return IStorage_DestroyElement(&This->base.IStorage_iface, name); }
-/************************************************************************ - * IPropertySetStorage_fnEnum (IPropertySetStorage) - */ -static HRESULT WINAPI IPropertySetStorage_fnEnum( - IPropertySetStorage *ppstg, - IEnumSTATPROPSETSTG** ppenum) -{ - StorageImpl *This = impl_from_IPropertySetStorage(ppstg); - return create_EnumSTATPROPSETSTG(This, ppenum); -} - -/************************************************************************ - * Implement IEnumSTATPROPSETSTG using enumx - */ -static HRESULT WINAPI IEnumSTATPROPSETSTG_fnQueryInterface( - IEnumSTATPROPSETSTG *iface, - REFIID riid, - void** ppvObject) -{ - return enumx_QueryInterface((enumx_impl*)iface, riid, ppvObject); -} - -static ULONG WINAPI IEnumSTATPROPSETSTG_fnAddRef( - IEnumSTATPROPSETSTG *iface) -{ - return enumx_AddRef((enumx_impl*)iface); -} - -static ULONG WINAPI IEnumSTATPROPSETSTG_fnRelease( - IEnumSTATPROPSETSTG *iface) +static HRESULT WINAPI IPropertySetStorage_fnEnum(IPropertySetStorage *iface, IEnumSTATPROPSETSTG **enum_obj) { - return enumx_Release((enumx_impl*)iface); -} + StorageImpl *storage = impl_from_IPropertySetStorage(iface);
-static HRESULT WINAPI IEnumSTATPROPSETSTG_fnNext( - IEnumSTATPROPSETSTG *iface, - ULONG celt, - STATPROPSETSTG *rgelt, - ULONG *pceltFetched) -{ - return enumx_Next((enumx_impl*)iface, celt, rgelt, pceltFetched); -} + TRACE("%p, %p.\n", iface, enum_obj);
-static HRESULT WINAPI IEnumSTATPROPSETSTG_fnSkip( - IEnumSTATPROPSETSTG *iface, - ULONG celt) -{ - return enumx_Skip((enumx_impl*)iface, celt); -} - -static HRESULT WINAPI IEnumSTATPROPSETSTG_fnReset( - IEnumSTATPROPSETSTG *iface) -{ - return enumx_Reset((enumx_impl*)iface); -} - -static HRESULT WINAPI IEnumSTATPROPSETSTG_fnClone( - IEnumSTATPROPSETSTG *iface, - IEnumSTATPROPSETSTG **ppenum) -{ - return enumx_Clone((enumx_impl*)iface, (enumx_impl**)ppenum); -} - -static HRESULT create_EnumSTATPROPSETSTG( - StorageImpl *This, - IEnumSTATPROPSETSTG** ppenum) -{ - IStorage *stg = &This->base.IStorage_iface; - IEnumSTATSTG *penum = NULL; - STATSTG stat; - ULONG count; - HRESULT r; - STATPROPSETSTG statpss; - enumx_impl *enumx; - - TRACE("%p %p\n", This, ppenum); - - enumx = enumx_allocate(&IID_IEnumSTATPROPSETSTG, - &IEnumSTATPROPSETSTG_Vtbl, - sizeof (STATPROPSETSTG)); - - /* add all the property set elements into a list */ - r = IStorage_EnumElements(stg, 0, NULL, 0, &penum); - if (FAILED(r)) - { - enumx_Release(enumx); - return E_OUTOFMEMORY; - } - - while (1) - { - count = 0; - r = IEnumSTATSTG_Next(penum, 1, &stat, &count); - if (FAILED(r)) - break; - if (!count) - break; - if (!stat.pwcsName) - continue; - if (stat.pwcsName[0] == 5 && stat.type == STGTY_STREAM) - { - PropStgNameToFmtId(stat.pwcsName, &statpss.fmtid); - TRACE("adding %s (%s)\n", debugstr_w(stat.pwcsName), - debugstr_guid(&statpss.fmtid)); - statpss.mtime = stat.mtime; - statpss.atime = stat.atime; - statpss.ctime = stat.ctime; - statpss.grfFlags = stat.grfMode; - statpss.clsid = stat.clsid; - enumx_add_element(enumx, &statpss); - } - CoTaskMemFree(stat.pwcsName); - } - IEnumSTATSTG_Release(penum); - - *ppenum = (IEnumSTATPROPSETSTG*) enumx; + if (!enum_obj) + return E_INVALIDARG;
- return S_OK; + return create_enum_stat_propset_stg(storage, enum_obj); }
/************************************************************************ @@ -2550,17 +2636,6 @@ static const IPropertyStorageVtbl IPropertyStorage_Vtbl = IPropertyStorage_fnStat, };
-static const IEnumSTATPROPSETSTGVtbl IEnumSTATPROPSETSTG_Vtbl = -{ - IEnumSTATPROPSETSTG_fnQueryInterface, - IEnumSTATPROPSETSTG_fnAddRef, - IEnumSTATPROPSETSTG_fnRelease, - IEnumSTATPROPSETSTG_fnNext, - IEnumSTATPROPSETSTG_fnSkip, - IEnumSTATPROPSETSTG_fnReset, - IEnumSTATPROPSETSTG_fnClone, -}; - static const IEnumSTATPROPSTGVtbl IEnumSTATPROPSTG_Vtbl = { IEnumSTATPROPSTG_fnQueryInterface, diff --git a/dlls/ole32/tests/stg_prop.c b/dlls/ole32/tests/stg_prop.c index 24ae03efc1..b2ed1a7081 100644 --- a/dlls/ole32/tests/stg_prop.c +++ b/dlls/ole32/tests/stg_prop.c @@ -669,10 +669,125 @@ static void testFmtId(void) } }
+static void test_propertyset_storage_enum(void) +{ + IPropertyStorage *prop_storage, *prop_storage2; + IPropertySetStorage *ps_storage; + IEnumSTATPROPSETSTG *ps_enum; + WCHAR filename[MAX_PATH]; + STATPROPSETSTG psstg; + DWORD ret, fetched; + IStorage *storage; + FILETIME ftime; + HRESULT hr; + + ret = GetTempFileNameW(L".", L"stg", 0, filename); + ok(ret, "Failed to get temporary file name.\n"); + + hr = StgCreateDocfile(filename, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0, &storage); + ok(hr == S_OK, "Failed to crate storage, hr %#x.\n", hr); + + hr = StgCreatePropSetStg(storage, 0, &ps_storage); + ok(hr == S_OK, "Failed to create property set storage, hr %#x.\n", hr); + + hr = IPropertySetStorage_Create(ps_storage, &FMTID_SummaryInformation, &IID_IUnknown, PROPSETFLAG_ANSI, + STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, &prop_storage); + ok(hr == S_OK, "Failed to create property storage, hr %#x.\n", hr); + + hr = IPropertyStorage_Stat(prop_storage, &psstg); + ok(hr == S_OK, "Failed to get prop storage stats, hr %#x.\n", hr); +todo_wine + ok(IsEqualCLSID(&psstg.clsid, &IID_IUnknown), "Unexpected storage clsid %s.\n", wine_dbgstr_guid(&psstg.clsid)); + + hr = IPropertySetStorage_Enum(ps_storage, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IPropertySetStorage_Enum(ps_storage, &ps_enum); + ok(hr == S_OK, "Failed to get enum object, hr %#x.\n", hr); + + memset(&psstg, 0, sizeof(psstg)); + hr = IEnumSTATPROPSETSTG_Next(ps_enum, 1, &psstg, &fetched); + ok(hr == S_OK, "Failed to get enum item, hr %#x.\n", hr); + ok(fetched == 1, "Unexpected fetched count.\n"); + ok(IsEqualCLSID(&psstg.fmtid, &FMTID_SummaryInformation), "Unexpected fmtid %s.\n", + wine_dbgstr_guid(&psstg.fmtid)); + ok(psstg.mtime.dwHighDateTime == 0 && psstg.mtime.dwLowDateTime == 0, "Unexpected mtime %#x / %#x.\n", + psstg.mtime.dwHighDateTime, psstg.mtime.dwLowDateTime); + + memset(&ftime, 0, sizeof(ftime)); + ftime.dwLowDateTime = 1; + hr = IPropertyStorage_SetTimes(prop_storage, NULL, NULL, &ftime); +todo_wine + ok(hr == S_OK, "Failed to set storage times, hr %#x.\n", hr); + + hr = IEnumSTATPROPSETSTG_Reset(ps_enum); + ok(hr == S_OK, "Failed to reset enumerator, hr %#x.\n", hr); + memset(&psstg, 0, sizeof(psstg)); + hr = IEnumSTATPROPSETSTG_Next(ps_enum, 1, &psstg, &fetched); + ok(hr == S_OK, "Failed to get enum item, hr %#x.\n", hr); + ok(fetched == 1, "Unexpected fetched count.\n"); + ok(IsEqualCLSID(&psstg.fmtid, &FMTID_SummaryInformation), "Unexpected fmtid %s.\n", + wine_dbgstr_guid(&psstg.fmtid)); + ok(psstg.mtime.dwHighDateTime == 0 && psstg.mtime.dwLowDateTime == 0, "Unexpected mtime %#x / %#x.\n", + psstg.mtime.dwHighDateTime, psstg.mtime.dwLowDateTime); + hr = IEnumSTATPROPSETSTG_Next(ps_enum, 1, &psstg, &fetched); + ok(hr == S_FALSE, "Unexpected hr #x.\n", hr); + + hr = IPropertySetStorage_Create(ps_storage, &FMTID_SummaryInformation, &IID_IUnknown, PROPSETFLAG_ANSI, + STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, &prop_storage2); + ok(hr == S_OK, "Failed to create property storage, hr %#x.\n", hr); + + hr = IEnumSTATPROPSETSTG_Reset(ps_enum); + ok(hr == S_OK, "Failed to reset enumerator, hr %#x.\n", hr); + hr = IEnumSTATPROPSETSTG_Next(ps_enum, 1, &psstg, &fetched); + ok(hr == S_OK, "Failed to get enum item, hr %#x.\n", hr); + ok(fetched == 1, "Unexpected fetched count.\n"); + hr = IEnumSTATPROPSETSTG_Next(ps_enum, 1, &psstg, &fetched); + ok(hr == S_FALSE, "Failed to get enum item, hr %#x.\n", hr); + + /* Skipping. */ + hr = IEnumSTATPROPSETSTG_Reset(ps_enum); + ok(hr == S_OK, "Failed to reset enumerator, hr %#x.\n", hr); + hr = IEnumSTATPROPSETSTG_Skip(ps_enum, 2); +todo_wine + ok(hr == S_FALSE, "Failed to skip, hr %#x.\n", hr); + hr = IEnumSTATPROPSETSTG_Next(ps_enum, 1, &psstg, &fetched); +todo_wine + ok(hr == S_FALSE, "Failed to get enum item, hr %#x.\n", hr); + + hr = IEnumSTATPROPSETSTG_Reset(ps_enum); + ok(hr == S_OK, "Failed to reset enumerator, hr %#x.\n", hr); + hr = IEnumSTATPROPSETSTG_Skip(ps_enum, 1); + ok(hr == S_OK, "Failed to skip, hr %#x.\n", hr); + hr = IEnumSTATPROPSETSTG_Next(ps_enum, 1, &psstg, &fetched); +todo_wine + ok(hr == S_FALSE, "Failed to get enum item, hr %#x.\n", hr); + + hr = IEnumSTATPROPSETSTG_Reset(ps_enum); + ok(hr == S_OK, "Failed to reset enumerator, hr %#x.\n", hr); +todo_wine { + hr = IEnumSTATPROPSETSTG_Skip(ps_enum, 0); + ok(hr == S_FALSE, "Failed to skip, hr %#x.\n", hr); + hr = IEnumSTATPROPSETSTG_Next(ps_enum, 1, &psstg, &fetched); + ok(hr == S_FALSE, "Failed to get enum item, hr %#x.\n", hr); +} + IEnumSTATPROPSETSTG_Release(ps_enum); + + IPropertyStorage_Release(prop_storage2); + IPropertyStorage_Release(prop_storage); + + IPropertySetStorage_Release(ps_storage); + IStorage_Release(storage); + + ret = DeleteFileW(filename); + ok(ret, "Failed to delete storage file.\n"); +} + START_TEST(stg_prop) { init_function_pointers(); testProps(); testCodepage(); testFmtId(); + test_propertyset_storage_enum(); }