Signed-off-by: Nikolay Sivov <nsivov(a)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();
}
--
2.24.0.rc1