[PATCH] ole32: Add separate enumerator implementation for IEnumSTATPROPSETSTG.

Nikolay Sivov nsivov at codeweavers.com
Fri Nov 8 07:33:52 CST 2019


Signed-off-by: Nikolay Sivov <nsivov at 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




More information about the wine-devel mailing list