Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/hnetcfg/port.c | 181 +++++++++++++++++++++++++++++++++++- dlls/hnetcfg/tests/policy.c | 11 ++- 2 files changed, 184 insertions(+), 8 deletions(-)
diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index 34e054527d9..8c80b02babc 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -735,6 +735,22 @@ static BOOL find_port_mapping( LONG port, BSTR protocol, struct port_mapping *re return found; }
+static unsigned int get_port_mapping_range( unsigned int index, unsigned int count, struct port_mapping *ret ) +{ + unsigned int i; + + AcquireSRWLockExclusive( &upnp_gateway_connection_lock ); + for (i = 0; i < count && index + i < upnp_gateway_connection.mapping_count; ++i) + if (!copy_port_mapping( &ret[i], &upnp_gateway_connection.mappings[index + i] )) + { + ERR( "No memory.\n" ); + break; + } + ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); + + return i; +} + static unsigned int get_port_mapping_count(void) { unsigned int ret; @@ -1048,6 +1064,164 @@ static HRESULT static_port_mapping_create( const struct port_mapping *mapping_da return S_OK; }
+struct port_mapping_enum +{ + IEnumVARIANT IEnumVARIANT_iface; + LONG refs; + unsigned int index; +}; + +static inline struct port_mapping_enum *impl_from_IEnumVARIANT( IEnumVARIANT *iface ) +{ + return CONTAINING_RECORD(iface, struct port_mapping_enum, IEnumVARIANT_iface); +} + +static ULONG WINAPI port_mapping_enum_AddRef( + IEnumVARIANT *iface ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + return InterlockedIncrement( &mapping_enum->refs ); +} + +static ULONG WINAPI port_mapping_enum_Release( + IEnumVARIANT *iface ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + LONG refs = InterlockedDecrement( &mapping_enum->refs ); + if (!refs) + { + TRACE("destroying %p\n", mapping_enum); + free( mapping_enum ); + release_gateway_connection(); + } + return refs; +} + +static HRESULT WINAPI port_mapping_enum_QueryInterface( + IEnumVARIANT *iface, + REFIID riid, + void **ppvObject ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + + TRACE("%p %s %p\n", mapping_enum, debugstr_guid( riid ), ppvObject ); + + if ( IsEqualGUID( riid, &IID_IEnumVARIANT ) || + IsEqualGUID( riid, &IID_IUnknown ) ) + { + *ppvObject = iface; + } + else + { + FIXME("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + IEnumVARIANT_AddRef( iface ); + return S_OK; +} + +static HRESULT WINAPI port_mapping_enum_Next( IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + struct port_mapping *data; + IStaticPortMapping *pm; + unsigned int i, count; + HRESULT ret; + + TRACE( "iface %p, celt %u, var %p, fetched %p.\n", iface, celt, var, fetched ); + + if (fetched) *fetched = 0; + if (!celt) return S_OK; + if (!var) return E_POINTER; + + if (!(data = calloc( 1, celt * sizeof(*data) ))) return E_OUTOFMEMORY; + count = get_port_mapping_range( mapping_enum->index, celt, data ); + TRACE( "count %u.\n", count ); + for (i = 0; i < count; ++i) + { + if (FAILED(static_port_mapping_create( &data[i], &pm ))) break; + + V_VT(&var[i]) = VT_DISPATCH; + V_DISPATCH(&var[i]) = (IDispatch *)pm; + } + mapping_enum->index += i; + if (fetched) *fetched = i; + ret = (i < celt) ? S_FALSE : S_OK; + for ( ; i < count; ++i) + { + free_port_mapping( &data[i] ); + VariantInit( &var[i] ); + } + for ( ; i < celt; ++i) + VariantInit( &var[i] ); + + free( data ); + return ret; +} + +static HRESULT WINAPI port_mapping_enum_Skip( IEnumVARIANT *iface, ULONG celt ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + unsigned int count = get_port_mapping_count(); + + TRACE( "iface %p, celt %u.\n", iface, celt ); + + mapping_enum->index += celt; + return mapping_enum->index <= count ? S_OK : S_FALSE; +} + +static HRESULT WINAPI port_mapping_enum_Reset( IEnumVARIANT *iface ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + + TRACE( "iface %p.\n", iface ); + + mapping_enum->index = 0; + return S_OK; +} + +static HRESULT create_port_mapping_enum( IUnknown **ret ); + +static HRESULT WINAPI port_mapping_enum_Clone( IEnumVARIANT *iface, IEnumVARIANT **ret ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + HRESULT hr; + + TRACE( "iface %p, ret %p.\n", iface, ret ); + + if (!ret) return E_POINTER; + *ret = NULL; + if (FAILED(hr = create_port_mapping_enum( (IUnknown **)ret ))) return hr; + impl_from_IEnumVARIANT( *ret )->index = mapping_enum->index; + return S_OK; +} + +static const IEnumVARIANTVtbl port_mapping_enum_vtbl = +{ + port_mapping_enum_QueryInterface, + port_mapping_enum_AddRef, + port_mapping_enum_Release, + port_mapping_enum_Next, + port_mapping_enum_Skip, + port_mapping_enum_Reset, + port_mapping_enum_Clone, +}; + +static HRESULT create_port_mapping_enum( IUnknown **ret ) +{ + struct port_mapping_enum *mapping_enum; + + if (!(mapping_enum = calloc( 1, sizeof(*mapping_enum) ))) return E_OUTOFMEMORY; + + grab_gateway_connection(); + + mapping_enum->refs = 1; + mapping_enum->IEnumVARIANT_iface.lpVtbl = &port_mapping_enum_vtbl; + mapping_enum->index = 0; + *ret = (IUnknown *)&mapping_enum->IEnumVARIANT_iface; + return S_OK; +} + struct static_port_mapping_collection { IStaticPortMappingCollection IStaticPortMappingCollection_iface; @@ -1183,11 +1357,12 @@ static HRESULT WINAPI static_ports__NewEnum( IStaticPortMappingCollection *iface, IUnknown **ret ) { - FIXME( "iface %p, ret %p stub.\n", iface, ret ); + TRACE( "iface %p, ret %p.\n", iface, ret );
- if (ret) *ret = NULL; + if (!ret) return E_POINTER;
- return E_NOTIMPL; + *ret = NULL; + return create_port_mapping_enum( ret ); }
static HRESULT WINAPI static_ports_get_Item( diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c index 19b6e3f6f2e..ffe3442dcd0 100644 --- a/dlls/hnetcfg/tests/policy.c +++ b/dlls/hnetcfg/tests/policy.c @@ -184,8 +184,7 @@ static void test_static_port_mapping_collection( IStaticPortMappingCollection *p
refcount = get_refcount((IUnknown *)ports); hr = IStaticPortMappingCollection_get__NewEnum(ports, &unk); - todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); - if (FAILED(hr)) return; + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
hr = IUnknown_QueryInterface(unk, &IID_IEnumVARIANT, (void **)&enum_ports); ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); @@ -213,14 +212,14 @@ static void test_static_port_mapping_collection( IStaticPortMappingCollection *p
hr = IStaticPortMappingCollection_Add(ports, 12345, (BSTR)L"udp", 12345, (BSTR)L"1.2.3.4", VARIANT_TRUE, (BSTR)L"wine_test", &pm); - ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); hr = IStaticPortMappingCollection_Add(ports, 12345, (BSTR)L"UDP", 12345, (BSTR)L"1.2.3.4", VARIANT_TRUE, (BSTR)L"wine_test", &pm); - ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
hr = IStaticPortMappingCollection_get_Count(ports, &count2); ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); - ok(count2 == expected_count, "Got unexpected count2 %u, expected %u.\n", count2, expected_count); + todo_wine ok(count2 == expected_count, "Got unexpected count2 %u, expected %u.\n", count2, expected_count);
hr = IStaticPortMappingCollection_get_Item(ports, 12345, NULL, &pm); ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); @@ -280,6 +279,8 @@ static void test_static_port_mapping_collection( IStaticPortMappingCollection *p
hr = IStaticPortMappingCollection_Remove(ports, 12345, (BSTR)L"UDP"); ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + hr = IStaticPortMappingCollection_Remove(ports, 12345, (BSTR)L"UDP"); + todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
IEnumVARIANT_Release(enum_ports); }