Commit 7279121f authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

ole32: Add separate enumerator implementation for IEnumSTATPROPSETSTG.

parent f51a80f4
......@@ -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)
static HRESULT WINAPI IPropertySetStorage_fnEnum(IPropertySetStorage *iface, IEnumSTATPROPSETSTG **enum_obj)
{
StorageImpl *This = impl_from_IPropertySetStorage(ppstg);
return create_EnumSTATPROPSETSTG(This, ppenum);
}
StorageImpl *storage = impl_from_IPropertySetStorage(iface);
/************************************************************************
* 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)
{
return enumx_Release((enumx_impl*)iface);
}
TRACE("%p, %p.\n", iface, enum_obj);
static HRESULT WINAPI IEnumSTATPROPSETSTG_fnNext(
IEnumSTATPROPSETSTG *iface,
ULONG celt,
STATPROPSETSTG *rgelt,
ULONG *pceltFetched)
{
return enumx_Next((enumx_impl*)iface, celt, rgelt, pceltFetched);
}
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,
......
......@@ -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();
}
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