Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/tests/opcservices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index f6194609ed..a9c25a5924 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -518,7 +518,7 @@ static void test_rel_part_uri(void) IOpcPartUri *rel_uri2; IOpcUri *source_uri2; IUnknown *unk = NULL; - BOOL ret; + BOOL ret = FALSE; BSTR str;
hr = IOpcPartUri_GetSourceUri(rel_uri, &source_uri);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/uri.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/opcservices/uri.c b/dlls/opcservices/uri.c index e461ebaa58..ddb2c05daf 100644 --- a/dlls/opcservices/uri.c +++ b/dlls/opcservices/uri.c @@ -476,6 +476,7 @@ static IUri *opc_part_uri_get_rels_uri(IUri *uri) if (FAILED(hr = CreateUri(ret, Uri_CREATE_ALLOW_RELATIVE, 0, &rels_uri))) WARN("Failed to create rels uri, hr %#x.\n", hr); heap_free(ret); + SysFreeString(path);
return rels_uri; }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/factory.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/dlls/opcservices/factory.c b/dlls/opcservices/factory.c index 1a98f3f49d..45e7ad71e4 100644 --- a/dlls/opcservices/factory.c +++ b/dlls/opcservices/factory.c @@ -331,7 +331,9 @@ static HRESULT WINAPI opc_factory_CreatePartUri(IOpcFactory *iface, LPCWSTR uri, return hr; }
- return opc_part_uri_create(part_uri, NULL, out); + hr = opc_part_uri_create(part_uri, NULL, out); + IUri_Release(part_uri); + return hr; }
static HRESULT WINAPI opc_factory_CreateStreamOnFile(IOpcFactory *iface, LPCWSTR filename,
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/tests/opcservices.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index a9c25a5924..0258bf2fef 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -75,6 +75,7 @@ static void test_package(void) hr = IOpcPackage_GetPartSet(package, &partset2); ok(SUCCEEDED(hr), "Failed to create a part set, hr %#x.\n", hr); ok(partset == partset2, "Expected same part set instance.\n"); + IOpcPartSet_Release(partset2);
/* CreatePart */ hr = IOpcFactory_CreatePartUri(factory, uriW, &part_uri); @@ -161,6 +162,7 @@ todo_wine { IOpcRelationshipSet_Release(relset); IOpcRelationshipSet_Release(relset2);
+ IOpcPartSet_Release(partset); IOpcPackage_Release(package);
/* Root uri */ @@ -322,6 +324,8 @@ static void test_relationship(void) hr = IOpcRelationshipSet_CreateRelationship(rels, NULL, typeW, target_uri2, OPC_URI_TARGET_MODE_INTERNAL, &rel); todo_wine ok(hr == OPC_E_INVALID_RELATIONSHIP_TARGET, "Unexpected hr %#x.\n", hr); + if (hr == S_OK) + IOpcRelationship_Release(rel);
hr = IOpcRelationshipSet_CreateRelationship(rels, NULL, typeW, target_uri, OPC_URI_TARGET_MODE_INTERNAL, &rel); ok(SUCCEEDED(hr), "Failed to create relationship, hr %#x.\n", hr);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/package.c | 187 ++++++++++++++++++++++++++- dlls/opcservices/tests/opcservices.c | 163 +++++++++++++++++++++++ include/opcbase.idl | 2 + 3 files changed, 350 insertions(+), 2 deletions(-)
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index c7ae2581cc..5ae5d3cf21 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -57,6 +57,16 @@ struct opc_package IOpcUri *source_uri; };
+struct opc_part_enum +{ + IOpcPartEnumerator IOpcPartEnumerator_iface; + LONG refcount; + + struct opc_part_set *part_set; + size_t pos; + GUID id; +}; + struct opc_part { IOpcPart IOpcPart_iface; @@ -77,6 +87,7 @@ struct opc_part_set struct opc_part **parts; size_t size; size_t count; + GUID id; };
struct opc_relationship @@ -132,6 +143,11 @@ static inline struct opc_content_stream *impl_from_IStream(IStream *iface) return CONTAINING_RECORD(iface, struct opc_content_stream, IStream_iface); }
+static inline struct opc_part_enum *impl_from_IOpcPartEnumerator(IOpcPartEnumerator *iface) +{ + return CONTAINING_RECORD(iface, struct opc_part_enum, IOpcPartEnumerator_iface); +} + static void opc_content_release(struct opc_content *content) { ULONG refcount = InterlockedDecrement(&content->refcount); @@ -143,6 +159,167 @@ static void opc_content_release(struct opc_content *content) } }
+static HRESULT opc_part_enum_create(struct opc_part_set *part_set, IOpcPartEnumerator **out); + +static HRESULT WINAPI opc_part_enum_QueryInterface(IOpcPartEnumerator *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualIID(&IID_IOpcPartEnumerator, iid) || + IsEqualIID(&IID_IUnknown, iid)) + { + *out = iface; + IOpcPartEnumerator_AddRef(iface); + return S_OK; + } + + *out = NULL; + WARN("Unsupported interface %s.\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI opc_part_enum_AddRef(IOpcPartEnumerator *iface) +{ + struct opc_part_enum *part_enum = impl_from_IOpcPartEnumerator(iface); + ULONG refcount = InterlockedIncrement(&part_enum->refcount); + + TRACE("%p increasing refcount to %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI opc_part_enum_Release(IOpcPartEnumerator *iface) +{ + struct opc_part_enum *part_enum = impl_from_IOpcPartEnumerator(iface); + ULONG refcount = InterlockedDecrement(&part_enum->refcount); + + TRACE("%p decreasing refcount to %u.\n", iface, refcount); + + if (!refcount) + { + IOpcPartSet_Release(&part_enum->part_set->IOpcPartSet_iface); + heap_free(part_enum); + } + + return refcount; +} + +static BOOL has_part_collection_changed(const struct opc_part_enum *part_enum) +{ + return !IsEqualGUID(&part_enum->id, &part_enum->part_set->id); +} + +static HRESULT WINAPI opc_part_enum_MoveNext(IOpcPartEnumerator *iface, BOOL *has_next) +{ + struct opc_part_enum *part_enum = impl_from_IOpcPartEnumerator(iface); + + TRACE("iface %p, has_next %p.\n", iface, has_next); + + if (!has_next) + return E_POINTER; + + if (has_part_collection_changed(part_enum)) + return OPC_E_ENUM_COLLECTION_CHANGED; + + if (part_enum->part_set->count && (part_enum->pos == ~(size_t)0 || part_enum->pos < part_enum->part_set->count)) + part_enum->pos++; + + *has_next = part_enum->pos < part_enum->part_set->count; + + return S_OK; +} + +static HRESULT WINAPI opc_part_enum_MovePrevious(IOpcPartEnumerator *iface, BOOL *has_previous) +{ + struct opc_part_enum *part_enum = impl_from_IOpcPartEnumerator(iface); + + TRACE("iface %p, has_previous %p.\n", iface, has_previous); + + if (!has_previous) + return E_POINTER; + + if (has_part_collection_changed(part_enum)) + return OPC_E_ENUM_COLLECTION_CHANGED; + + if (part_enum->pos != ~(size_t)0) + part_enum->pos--; + + *has_previous = part_enum->pos != ~(size_t)0; + + return S_OK; +} + +static HRESULT WINAPI opc_part_enum_GetCurrent(IOpcPartEnumerator *iface, IOpcPart **part) +{ + struct opc_part_enum *part_enum = impl_from_IOpcPartEnumerator(iface); + + TRACE("iface %p, part %p.\n", iface, part); + + if (!part) + return E_POINTER; + + *part = NULL; + + if (has_part_collection_changed(part_enum)) + return OPC_E_ENUM_COLLECTION_CHANGED; + + if (part_enum->pos < part_enum->part_set->count) + { + *part = &part_enum->part_set->parts[part_enum->pos]->IOpcPart_iface; + IOpcPart_AddRef(*part); + } + + return *part ? S_OK : OPC_E_ENUM_INVALID_POSITION; +} + +static HRESULT WINAPI opc_part_enum_Clone(IOpcPartEnumerator *iface, IOpcPartEnumerator **out) +{ + struct opc_part_enum *part_enum = impl_from_IOpcPartEnumerator(iface); + + TRACE("iface %p, out %p.\n", iface, out); + + if (!out) + return E_POINTER; + + if (has_part_collection_changed(part_enum)) + { + *out = NULL; + return OPC_E_ENUM_COLLECTION_CHANGED; + } + + return opc_part_enum_create(part_enum->part_set, out); +} + +static const IOpcPartEnumeratorVtbl opc_part_enum_vtbl = +{ + opc_part_enum_QueryInterface, + opc_part_enum_AddRef, + opc_part_enum_Release, + opc_part_enum_MoveNext, + opc_part_enum_MovePrevious, + opc_part_enum_GetCurrent, + opc_part_enum_Clone, +}; + +static HRESULT opc_part_enum_create(struct opc_part_set *part_set, IOpcPartEnumerator **out) +{ + struct opc_part_enum *part_enum; + + if (!(part_enum = heap_alloc_zero(sizeof(*part_enum)))) + return E_OUTOFMEMORY; + + part_enum->IOpcPartEnumerator_iface.lpVtbl = &opc_part_enum_vtbl; + part_enum->refcount = 1; + part_enum->part_set = part_set; + IOpcPartSet_AddRef(&part_set->IOpcPartSet_iface); + part_enum->pos = ~(size_t)0; + part_enum->id = part_set->id; + + *out = &part_enum->IOpcPartEnumerator_iface; + TRACE("Created part enumerator %p.\n", *out); + return S_OK; +} + static HRESULT WINAPI opc_content_stream_QueryInterface(IStream *iface, REFIID iid, void **out) { TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -536,6 +713,7 @@ static HRESULT opc_part_create(struct opc_part_set *set, IOpcPartUri *name, cons
set->parts[set->count++] = part; IOpcPart_AddRef(&part->IOpcPart_iface); + CoCreateGuid(&set->id);
*out = &part->IOpcPart_iface; TRACE("Created part %p.\n", *out); @@ -622,9 +800,14 @@ static HRESULT WINAPI opc_part_set_PartExists(IOpcPartSet *iface, IOpcPartUri *n
static HRESULT WINAPI opc_part_set_GetEnumerator(IOpcPartSet *iface, IOpcPartEnumerator **enumerator) { - FIXME("iface %p, enumerator %p stub!\n", iface, enumerator); + struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
- return E_NOTIMPL; + TRACE("iface %p, enumerator %p.\n", iface, enumerator); + + if (!enumerator) + return E_POINTER; + + return opc_part_enum_create(part_set, enumerator); }
static const IOpcPartSetVtbl opc_part_set_vtbl = diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index 0258bf2fef..67e5ffff54 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -591,6 +591,168 @@ static void test_rel_part_uri(void) IOpcFactory_Release(factory); }
+static void test_part_enumerator(void) +{ + static const WCHAR typeW[] = {'t','y','p','e','/','s','u','b','t','y','p','e',0}; + static const WCHAR uriW[] = {'/','u','r','i',0}; + IOpcPartEnumerator *partenum, *partenum2; + IOpcPart *part, *part2; + IOpcPartUri *part_uri; + IOpcPackage *package; + IOpcFactory *factory; + IOpcPartSet *parts; + HRESULT hr; + BOOL ret; + + factory = create_factory(); + + hr = IOpcFactory_CreatePackage(factory, &package); + ok(SUCCEEDED(hr) || broken(hr == E_NOTIMPL) /* Vista */, "Failed to create a package, hr %#x.\n", hr); + if (FAILED(hr)) + { + IOpcFactory_Release(factory); + return; + } + + hr = IOpcPackage_GetPartSet(package, &parts); + ok(SUCCEEDED(hr), "Failed to get part set, hr %#x.\n", hr); + + hr = IOpcPartSet_GetEnumerator(parts, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IOpcPartSet_GetEnumerator(parts, &partenum); + ok(SUCCEEDED(hr), "Failed to get enumerator, hr %#x.\n", hr); + + hr = IOpcPartSet_GetEnumerator(parts, &partenum2); + ok(SUCCEEDED(hr), "Failed to get enumerator, hr %#x.\n", hr); + ok(partenum != partenum2, "Unexpected instance.\n"); + IOpcPartEnumerator_Release(partenum2); + + hr = IOpcPartEnumerator_GetCurrent(partenum, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IOpcPartEnumerator_GetCurrent(partenum, &part); + ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr); + + hr = IOpcPartEnumerator_MoveNext(partenum, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + ret = TRUE; + hr = IOpcPartEnumerator_MoveNext(partenum, &ret); + ok(hr == S_OK, "Failed to move, hr %#x.\n", hr); + ok(!ret, "Unexpected result %d.\n", ret); + + ret = TRUE; + hr = IOpcPartEnumerator_MovePrevious(partenum, &ret); + ok(hr == S_OK, "Failed to move, hr %#x.\n", hr); + ok(!ret, "Unexpected result %d.\n", ret); + + hr = IOpcFactory_CreatePartUri(factory, uriW, &part_uri); + ok(SUCCEEDED(hr), "Failed to create part uri, hr %#x.\n", hr); + + hr = IOpcPartSet_CreatePart(parts, part_uri, typeW, OPC_COMPRESSION_NONE, &part); + ok(SUCCEEDED(hr), "Failed to create a part, hr %#x.\n", hr); + IOpcPartUri_Release(part_uri); + + part2 = (void *)0xdeadbeef; + hr = IOpcPartEnumerator_GetCurrent(partenum, &part2); + ok(hr == OPC_E_ENUM_COLLECTION_CHANGED, "Unexpected hr %#x.\n", hr); + ok(part2 == NULL, "Unexpected instance.\n"); + + hr = IOpcPartEnumerator_MoveNext(partenum, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + ret = 123; + hr = IOpcPartEnumerator_MoveNext(partenum, &ret); + ok(hr == OPC_E_ENUM_COLLECTION_CHANGED, "Unexpected hr %#x.\n", hr); + ok(ret == 123, "Unexpected result %d.\n", ret); + + hr = IOpcPartEnumerator_MovePrevious(partenum, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + ret = 123; + hr = IOpcPartEnumerator_MovePrevious(partenum, &ret); + ok(hr == OPC_E_ENUM_COLLECTION_CHANGED, "Unexpected hr %#x.\n", hr); + ok(ret == 123, "Unexpected result %d.\n", ret); + + hr = IOpcPartEnumerator_Clone(partenum, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + partenum2 = (void *)0xdeadbeef; + hr = IOpcPartEnumerator_Clone(partenum, &partenum2); + ok(hr == OPC_E_ENUM_COLLECTION_CHANGED, "Unexpected hr %#x.\n", hr); + ok(partenum2 == NULL, "Unexpected instance.\n"); + + IOpcPartEnumerator_Release(partenum); + + hr = IOpcPartSet_GetEnumerator(parts, &partenum); + ok(SUCCEEDED(hr), "Failed to get enumerator, hr %#x.\n", hr); + + part2 = (void *)0xdeadbeef; + hr = IOpcPartEnumerator_GetCurrent(partenum, &part2); + ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr); + ok(part2 == NULL, "Unexpected instance.\n"); + + hr = IOpcPartEnumerator_MoveNext(partenum, &ret); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(ret, "Unexpected result %d.\n", ret); + + hr = IOpcPartEnumerator_GetCurrent(partenum, &part2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(part2 == part, "Unexpected instance.\n"); + IOpcPart_Release(part2); + + hr = IOpcPartEnumerator_MoveNext(partenum, &ret); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!ret, "Unexpected result %d.\n", ret); + + part2 = (void *)0xdeadbeef; + hr = IOpcPartEnumerator_GetCurrent(partenum, &part2); + ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr); + ok(part2 == NULL, "Unexpected instance.\n"); + + hr = IOpcPartEnumerator_MovePrevious(partenum, &ret); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(ret, "Unexpected result %d.\n", ret); + + hr = IOpcPartEnumerator_GetCurrent(partenum, &part2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(part2 == part, "Unexpected instance.\n"); + IOpcPart_Release(part2); + + hr = IOpcPartEnumerator_MovePrevious(partenum, &ret); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!ret, "Unexpected result %d.\n", ret); + + hr = IOpcPartEnumerator_GetCurrent(partenum, &part2); + ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr); + + hr = IOpcPartEnumerator_Clone(partenum, &partenum2); + ok(SUCCEEDED(hr), "Clone failed, hr %#x.\n", hr); + + hr = IOpcPartEnumerator_MoveNext(partenum2, &ret); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(ret, "Unexpected result %d.\n", ret); + + hr = IOpcPartEnumerator_GetCurrent(partenum2, &part2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + IOpcPart_Release(part2); + + hr = IOpcPartEnumerator_GetCurrent(partenum, &part2); + ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr); + + IOpcPartEnumerator_Release(partenum2); + + IOpcPartEnumerator_Release(partenum); + + IOpcPart_Release(part); + + IOpcPartSet_Release(parts); + + IOpcPackage_Release(package); + IOpcFactory_Release(factory); +} + START_TEST(opcservices) { IOpcFactory *factory; @@ -609,6 +771,7 @@ START_TEST(opcservices) test_file_stream(); test_relationship(); test_rel_part_uri(); + test_part_enumerator();
IOpcFactory_Release(factory);
diff --git a/include/opcbase.idl b/include/opcbase.idl index fae5858ed6..8523271217 100644 --- a/include/opcbase.idl +++ b/include/opcbase.idl @@ -45,3 +45,5 @@ cpp_quote("#define OPC_E_NONCONFORMING_URI MAKE_HRESULT(SEVERITY_ERROR, FACILITY cpp_quote("#define OPC_E_RELATIONSHIP_URI_REQUIRED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x3)") cpp_quote("#define OPC_E_INVALID_RELATIONSHIP_TARGET MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x12)") cpp_quote("#define OPC_E_NO_SUCH_RELATIONSHIP MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x48)") +cpp_quote("#define OPC_E_ENUM_COLLECTION_CHANGED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x50)") +cpp_quote("#define OPC_E_ENUM_INVALID_POSITION MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x53)")
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/package.c | 187 ++++++++++++++++++++++++++- dlls/opcservices/tests/opcservices.c | 163 +++++++++++++++++++++++ 2 files changed, 348 insertions(+), 2 deletions(-)
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index 5ae5d3cf21..eb9c1c9f5a 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -90,6 +90,16 @@ struct opc_part_set GUID id; };
+struct opc_rel_enum +{ + IOpcRelationshipEnumerator IOpcRelationshipEnumerator_iface; + LONG refcount; + + struct opc_relationship_set *rel_set; + size_t pos; + GUID id; +}; + struct opc_relationship { IOpcRelationship IOpcRelationship_iface; @@ -111,6 +121,7 @@ struct opc_relationship_set size_t size; size_t count; IOpcUri *source_uri; + GUID id; };
static inline struct opc_package *impl_from_IOpcPackage(IOpcPackage *iface) @@ -148,6 +159,11 @@ static inline struct opc_part_enum *impl_from_IOpcPartEnumerator(IOpcPartEnumera return CONTAINING_RECORD(iface, struct opc_part_enum, IOpcPartEnumerator_iface); }
+static inline struct opc_rel_enum *impl_from_IOpcRelationshipEnumerator(IOpcRelationshipEnumerator *iface) +{ + return CONTAINING_RECORD(iface, struct opc_rel_enum, IOpcRelationshipEnumerator_iface); +} + static void opc_content_release(struct opc_content *content) { ULONG refcount = InterlockedDecrement(&content->refcount); @@ -320,6 +336,167 @@ static HRESULT opc_part_enum_create(struct opc_part_set *part_set, IOpcPartEnume return S_OK; }
+static HRESULT opc_rel_enum_create(struct opc_relationship_set *rel_set, IOpcRelationshipEnumerator **out); + +static HRESULT WINAPI opc_rel_enum_QueryInterface(IOpcRelationshipEnumerator *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualIID(&IID_IOpcRelationshipEnumerator, iid) || + IsEqualIID(&IID_IUnknown, iid)) + { + *out = iface; + IOpcRelationshipEnumerator_AddRef(iface); + return S_OK; + } + + *out = NULL; + WARN("Unsupported interface %s.\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI opc_rel_enum_AddRef(IOpcRelationshipEnumerator *iface) +{ + struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface); + ULONG refcount = InterlockedIncrement(&rel_enum->refcount); + + TRACE("%p increasing refcount to %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI opc_rel_enum_Release(IOpcRelationshipEnumerator *iface) +{ + struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface); + ULONG refcount = InterlockedDecrement(&rel_enum->refcount); + + TRACE("%p decreasing refcount to %u.\n", iface, refcount); + + if (!refcount) + { + IOpcRelationshipSet_Release(&rel_enum->rel_set->IOpcRelationshipSet_iface); + heap_free(rel_enum); + } + + return refcount; +} + +static BOOL has_rel_collection_changed(const struct opc_rel_enum *rel_enum) +{ + return !IsEqualGUID(&rel_enum->id, &rel_enum->rel_set->id); +} + +static HRESULT WINAPI opc_rel_enum_MoveNext(IOpcRelationshipEnumerator *iface, BOOL *has_next) +{ + struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface); + + TRACE("iface %p, has_next %p.\n", iface, has_next); + + if (!has_next) + return E_POINTER; + + if (has_rel_collection_changed(rel_enum)) + return OPC_E_ENUM_COLLECTION_CHANGED; + + if (rel_enum->rel_set->count && (rel_enum->pos == ~(size_t)0 || rel_enum->pos < rel_enum->rel_set->count)) + rel_enum->pos++; + + *has_next = rel_enum->pos < rel_enum->rel_set->count; + + return S_OK; +} + +static HRESULT WINAPI opc_rel_enum_MovePrevious(IOpcRelationshipEnumerator *iface, BOOL *has_previous) +{ + struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface); + + TRACE("iface %p, has_previous %p.\n", iface, has_previous); + + if (!has_previous) + return E_POINTER; + + if (has_rel_collection_changed(rel_enum)) + return OPC_E_ENUM_COLLECTION_CHANGED; + + if (rel_enum->pos != ~(size_t)0) + rel_enum->pos--; + + *has_previous = rel_enum->pos != ~(size_t)0; + + return S_OK; +} + +static HRESULT WINAPI opc_rel_enum_GetCurrent(IOpcRelationshipEnumerator *iface, IOpcRelationship **rel) +{ + struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface); + + TRACE("iface %p, rel %p.\n", iface, rel); + + if (!rel) + return E_POINTER; + + *rel = NULL; + + if (has_rel_collection_changed(rel_enum)) + return OPC_E_ENUM_COLLECTION_CHANGED; + + if (rel_enum->pos < rel_enum->rel_set->count) + { + *rel = &rel_enum->rel_set->relationships[rel_enum->pos]->IOpcRelationship_iface; + IOpcRelationship_AddRef(*rel); + } + + return *rel ? S_OK : OPC_E_ENUM_INVALID_POSITION; +} + +static HRESULT WINAPI opc_rel_enum_Clone(IOpcRelationshipEnumerator *iface, IOpcRelationshipEnumerator **out) +{ + struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface); + + TRACE("iface %p, out %p.\n", iface, out); + + if (!out) + return E_POINTER; + + if (has_rel_collection_changed(rel_enum)) + { + *out = NULL; + return OPC_E_ENUM_COLLECTION_CHANGED; + } + + return opc_rel_enum_create(rel_enum->rel_set, out); +} + +static const IOpcRelationshipEnumeratorVtbl opc_rel_enum_vtbl = +{ + opc_rel_enum_QueryInterface, + opc_rel_enum_AddRef, + opc_rel_enum_Release, + opc_rel_enum_MoveNext, + opc_rel_enum_MovePrevious, + opc_rel_enum_GetCurrent, + opc_rel_enum_Clone, +}; + +static HRESULT opc_rel_enum_create(struct opc_relationship_set *rel_set, IOpcRelationshipEnumerator **out) +{ + struct opc_rel_enum *rel_enum; + + if (!(rel_enum = heap_alloc_zero(sizeof(*rel_enum)))) + return E_OUTOFMEMORY; + + rel_enum->IOpcRelationshipEnumerator_iface.lpVtbl = &opc_rel_enum_vtbl; + rel_enum->refcount = 1; + rel_enum->rel_set = rel_set; + IOpcRelationshipSet_AddRef(&rel_set->IOpcRelationshipSet_iface); + rel_enum->pos = ~(size_t)0; + rel_enum->id = rel_set->id; + + *out = &rel_enum->IOpcRelationshipEnumerator_iface; + TRACE("Created relationship enumerator %p.\n", *out); + return S_OK; +} + static HRESULT WINAPI opc_content_stream_QueryInterface(IStream *iface, REFIID iid, void **out) { TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -978,6 +1155,7 @@ static HRESULT opc_relationship_create(struct opc_relationship_set *set, const W
set->relationships[set->count++] = relationship; IOpcRelationship_AddRef(&relationship->IOpcRelationship_iface); + CoCreateGuid(&set->id);
*out = &relationship->IOpcRelationship_iface; TRACE("Created relationship %p.\n", *out); @@ -1108,9 +1286,14 @@ static HRESULT WINAPI opc_relationship_set_RelationshipExists(IOpcRelationshipSe static HRESULT WINAPI opc_relationship_set_GetEnumerator(IOpcRelationshipSet *iface, IOpcRelationshipEnumerator **enumerator) { - FIXME("iface %p, enumerator %p stub!\n", iface, enumerator); + struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
- return E_NOTIMPL; + TRACE("iface %p, enumerator %p.\n", iface, enumerator); + + if (!enumerator) + return E_POINTER; + + return opc_rel_enum_create(relationship_set, enumerator); }
static HRESULT WINAPI opc_relationship_set_GetEnumeratorForType(IOpcRelationshipSet *iface, const WCHAR *type, diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index 67e5ffff54..936e2c751d 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -753,6 +753,168 @@ static void test_part_enumerator(void) IOpcFactory_Release(factory); }
+static void test_rels_enumerator(void) +{ + static const WCHAR typeW[] = {'t','y','p','e','/','s','u','b','t','y','p','e',0}; + static const WCHAR targetW[] = {'t','a','r','g','e','t',0}; + IOpcRelationshipEnumerator *relsenum, *relsenum2; + IOpcRelationship *rel, *rel2; + IOpcPackage *package; + IOpcFactory *factory; + IOpcRelationshipSet *rels; + IUri *target_uri; + HRESULT hr; + BOOL ret; + + factory = create_factory(); + + hr = IOpcFactory_CreatePackage(factory, &package); + ok(SUCCEEDED(hr) || broken(hr == E_NOTIMPL) /* Vista */, "Failed to create a package, hr %#x.\n", hr); + if (FAILED(hr)) + { + IOpcFactory_Release(factory); + return; + } + + hr = IOpcPackage_GetRelationshipSet(package, &rels); + ok(SUCCEEDED(hr), "Failed to get part set, hr %#x.\n", hr); + + hr = IOpcRelationshipSet_GetEnumerator(rels, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IOpcRelationshipSet_GetEnumerator(rels, &relsenum); + ok(SUCCEEDED(hr), "Failed to get enumerator, hr %#x.\n", hr); + + hr = IOpcRelationshipSet_GetEnumerator(rels, &relsenum2); + ok(SUCCEEDED(hr), "Failed to get enumerator, hr %#x.\n", hr); + ok(relsenum != relsenum2, "Unexpected instance.\n"); + IOpcRelationshipEnumerator_Release(relsenum2); + + hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel); + ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr); + + hr = IOpcRelationshipEnumerator_MoveNext(relsenum, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + ret = TRUE; + hr = IOpcRelationshipEnumerator_MoveNext(relsenum, &ret); + ok(hr == S_OK, "Failed to move, hr %#x.\n", hr); + ok(!ret, "Unexpected result %d.\n", ret); + + ret = TRUE; + hr = IOpcRelationshipEnumerator_MovePrevious(relsenum, &ret); + ok(hr == S_OK, "Failed to move, hr %#x.\n", hr); + ok(!ret, "Unexpected result %d.\n", ret); + + hr = CreateUri(targetW, Uri_CREATE_ALLOW_RELATIVE, 0, &target_uri); + ok(SUCCEEDED(hr), "Failed to create target uri, hr %#x.\n", hr); + + hr = IOpcRelationshipSet_CreateRelationship(rels, NULL, typeW, target_uri, OPC_URI_TARGET_MODE_INTERNAL, &rel); + ok(SUCCEEDED(hr), "Failed to create relationship, hr %#x.\n", hr); + + IUri_Release(target_uri); + + rel2 = (void *)0xdeadbeef; + hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2); + ok(hr == OPC_E_ENUM_COLLECTION_CHANGED, "Unexpected hr %#x.\n", hr); + ok(rel2 == NULL, "Unexpected instance.\n"); + + hr = IOpcRelationshipEnumerator_MoveNext(relsenum, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + ret = 123; + hr = IOpcRelationshipEnumerator_MoveNext(relsenum, &ret); + ok(hr == OPC_E_ENUM_COLLECTION_CHANGED, "Unexpected hr %#x.\n", hr); + ok(ret == 123, "Unexpected result %d.\n", ret); + + hr = IOpcRelationshipEnumerator_MovePrevious(relsenum, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + ret = 123; + hr = IOpcRelationshipEnumerator_MovePrevious(relsenum, &ret); + ok(hr == OPC_E_ENUM_COLLECTION_CHANGED, "Unexpected hr %#x.\n", hr); + ok(ret == 123, "Unexpected result %d.\n", ret); + + hr = IOpcRelationshipEnumerator_Clone(relsenum, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + relsenum2 = (void *)0xdeadbeef; + hr = IOpcRelationshipEnumerator_Clone(relsenum, &relsenum2); + ok(hr == OPC_E_ENUM_COLLECTION_CHANGED, "Unexpected hr %#x.\n", hr); + ok(relsenum2 == NULL, "Unexpected instance.\n"); + + IOpcRelationshipEnumerator_Release(relsenum); + + hr = IOpcRelationshipSet_GetEnumerator(rels, &relsenum); + ok(SUCCEEDED(hr), "Failed to get enumerator, hr %#x.\n", hr); + + rel2 = (void *)0xdeadbeef; + hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2); + ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr); + ok(rel2 == NULL, "Unexpected instance.\n"); + + hr = IOpcRelationshipEnumerator_MoveNext(relsenum, &ret); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(ret, "Unexpected result %d.\n", ret); + + hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(rel2 == rel, "Unexpected instance.\n"); + IOpcRelationship_Release(rel2); + + hr = IOpcRelationshipEnumerator_MoveNext(relsenum, &ret); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!ret, "Unexpected result %d.\n", ret); + + rel2 = (void *)0xdeadbeef; + hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2); + ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr); + ok(rel2 == NULL, "Unexpected instance.\n"); + + hr = IOpcRelationshipEnumerator_MovePrevious(relsenum, &ret); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(ret, "Unexpected result %d.\n", ret); + + hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(rel2 == rel, "Unexpected instance.\n"); + IOpcRelationship_Release(rel2); + + hr = IOpcRelationshipEnumerator_MovePrevious(relsenum, &ret); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!ret, "Unexpected result %d.\n", ret); + + hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2); + ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr); + + hr = IOpcRelationshipEnumerator_Clone(relsenum, &relsenum2); + ok(SUCCEEDED(hr), "Clone failed, hr %#x.\n", hr); + + hr = IOpcRelationshipEnumerator_MoveNext(relsenum2, &ret); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(ret, "Unexpected result %d.\n", ret); + + hr = IOpcRelationshipEnumerator_GetCurrent(relsenum2, &rel2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + IOpcRelationship_Release(rel2); + + hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2); + ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr); + + IOpcRelationshipEnumerator_Release(relsenum2); + + IOpcRelationshipEnumerator_Release(relsenum); + + IOpcRelationship_Release(rel); + + IOpcRelationshipSet_Release(rels); + + IOpcPackage_Release(package); + IOpcFactory_Release(factory); +} START_TEST(opcservices) { IOpcFactory *factory; @@ -772,6 +934,7 @@ START_TEST(opcservices) test_relationship(); test_rel_part_uri(); test_part_enumerator(); + test_rels_enumerator();
IOpcFactory_Release(factory);