[PATCH v2 0/2] MR11200: dnsapi: Implement DnsServiceConstructInstance() and DnsServiceFreeInstance().
`DnsServiceConstructInstance` and `DnsServiceFreeInstance` are missing from dnsapi. Applications that import them abort at startup on the unimplemented function. The Elgato Stream Deck software hits this: it calls `DnsServiceConstructInstance` to build an mDNS service instance (for example \_vstreamdeck2.\_tcp.local) before advertising it. `DnsServiceConstructInstance` builds a DNS_SERVICE_INSTANCE from its arguments and `DnsServiceFreeInstance` releases it. Neither touches the network, so they are implemented directly. The change also adds the DNS_SERVICE_INSTANCE structure and the two prototypes to windns.h. `DnsServiceRegister`, which the same applications call next to publish the instance, is still missing and will abort. That needs real mDNS support. Signed-off-by: Thomas Portal portal.thomas@protonmail.com -- v2: dnsapi/tests: Add tests for DnsServiceConstructInstance(). dnsapi: Implement DnsServiceConstructInstance() and DnsServiceFreeInstance(). https://gitlab.winehq.org/wine/wine/-/merge_requests/11200
From: Thomas Portal <portal.thomas@protonmail.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59891 Signed-off-by: Thomas Portal <portal.thomas@protonmail.com> --- dlls/dnsapi/dnsapi.spec | 2 ++ dlls/dnsapi/main.c | 59 +++++++++++++++++++++++++++++++++++++++++ include/windns.h | 17 ++++++++++++ 3 files changed, 78 insertions(+) diff --git a/dlls/dnsapi/dnsapi.spec b/dlls/dnsapi/dnsapi.spec index a8ffa40a0ae..a9bac0a1375 100644 --- a/dlls/dnsapi/dnsapi.spec +++ b/dlls/dnsapi/dnsapi.spec @@ -104,6 +104,8 @@ @ stdcall DnsReplaceRecordSetW(ptr long ptr ptr ptr) @ stub DnsReplaceRecordSet_W @ stdcall DnsServiceBrowse(ptr ptr) +@ stdcall DnsServiceConstructInstance(wstr wstr ptr ptr long long long long ptr ptr) +@ stdcall DnsServiceFreeInstance(ptr) @ stub DnsServiceNotificationDeregister_A @ stub DnsServiceNotificationDeregister_UTF8 @ stub DnsServiceNotificationDeregister_W diff --git a/dlls/dnsapi/main.c b/dlls/dnsapi/main.c index 9b057a09a05..07411243c0f 100644 --- a/dlls/dnsapi/main.c +++ b/dlls/dnsapi/main.c @@ -243,3 +243,62 @@ DNS_STATUS WINAPI DnsServiceBrowse( PDNS_SERVICE_BROWSE_REQUEST request, PDNS_SE FIXME( "(%p, %p) stub\n", request, cancel ); return ERROR_SUCCESS; } + +/****************************************************************************** + * DnsServiceConstructInstance [DNSAPI.@] + * + */ +PDNS_SERVICE_INSTANCE WINAPI DnsServiceConstructInstance( PCWSTR name, PCWSTR host, + PIP4_ADDRESS ip4, PIP6_ADDRESS ip6, WORD port, WORD priority, WORD weight, + DWORD count, PCWSTR *keys, PCWSTR *values ) +{ + DNS_SERVICE_INSTANCE *instance; + DWORD i; + + TRACE( "(%s, %s, %p, %p, %u, %u, %u, %lu, %p, %p)\n", debugstr_w(name), debugstr_w(host), + ip4, ip6, port, priority, weight, count, keys, values ); + + if (!(instance = calloc( 1, sizeof(*instance) ))) return NULL; + + if (name) instance->pszInstanceName = wcsdup( name ); + if (host) instance->pszHostName = wcsdup( host ); + if (ip4 && (instance->ip4Address = malloc( sizeof(*ip4) ))) *instance->ip4Address = *ip4; + if (ip6 && (instance->ip6Address = malloc( sizeof(*ip6) ))) *instance->ip6Address = *ip6; + instance->wPort = port; + instance->wPriority = priority; + instance->wWeight = weight; + instance->dwPropertyCount = count; + + if (count && (instance->keys = calloc( count, sizeof(*keys) ))) + for (i = 0; i < count; i++) instance->keys[i] = wcsdup( keys[i] ); + if (count && (instance->values = calloc( count, sizeof(*values) ))) + for (i = 0; i < count; i++) instance->values[i] = wcsdup( values[i] ); + + return instance; +} + +/****************************************************************************** + * DnsServiceFreeInstance [DNSAPI.@] + * + */ +void WINAPI DnsServiceFreeInstance( PDNS_SERVICE_INSTANCE instance ) +{ + DWORD i; + + TRACE( "(%p)\n", instance ); + + if (!instance) return; + + free( instance->pszInstanceName ); + free( instance->pszHostName ); + free( instance->ip4Address ); + free( instance->ip6Address ); + for (i = 0; i < instance->dwPropertyCount; i++) + { + if (instance->keys) free( instance->keys[i] ); + if (instance->values) free( instance->values[i] ); + } + free( instance->keys ); + free( instance->values ); + free( instance ); +} diff --git a/include/windns.h b/include/windns.h index 87e8dad37da..544b02bbfdc 100644 --- a/include/windns.h +++ b/include/windns.h @@ -781,6 +781,21 @@ typedef struct _DNS_SERVICE_CANCEL void *reserved; } DNS_SERVICE_CANCEL, *PDNS_SERVICE_CANCEL; +typedef struct _DNS_SERVICE_INSTANCE +{ + LPWSTR pszInstanceName; + LPWSTR pszHostName; + IP4_ADDRESS *ip4Address; + IP6_ADDRESS *ip6Address; + WORD wPort; + WORD wPriority; + WORD wWeight; + DWORD dwPropertyCount; + PWSTR *keys; + PWSTR *values; + DWORD dwInterfaceIndex; +} DNS_SERVICE_INSTANCE, *PDNS_SERVICE_INSTANCE; + DNS_STATUS WINAPI DnsAcquireContextHandle_A(DWORD,PVOID,PHANDLE); DNS_STATUS WINAPI DnsAcquireContextHandle_W(DWORD,PVOID,PHANDLE); #define DnsAcquireContextHandle WINELIB_NAME_AW(DnsAcquireContextHandle_) @@ -813,6 +828,8 @@ DNS_STATUS WINAPI DnsReplaceRecordSetW(PDNS_RECORDW,DWORD,HANDLE,PVOID,PVOID); DNS_STATUS WINAPI DnsReplaceRecordSetUTF8(PDNS_RECORDA,DWORD,HANDLE,PVOID,PVOID); #define DnsReplaceRecordSet WINELIB_NAME_AW(DnsReplaceRecordSet) DNS_STATUS WINAPI DnsServiceBrowse(PDNS_SERVICE_BROWSE_REQUEST, PDNS_SERVICE_CANCEL); +PDNS_SERVICE_INSTANCE WINAPI DnsServiceConstructInstance(PCWSTR,PCWSTR,PIP4_ADDRESS,PIP6_ADDRESS,WORD,WORD,WORD,DWORD,PCWSTR*,PCWSTR*); +VOID WINAPI DnsServiceFreeInstance(PDNS_SERVICE_INSTANCE); DNS_STATUS WINAPI DnsValidateName_A(PCSTR,DNS_NAME_FORMAT); DNS_STATUS WINAPI DnsValidateName_W(PCWSTR, DNS_NAME_FORMAT); DNS_STATUS WINAPI DnsValidateName_UTF8(PCSTR,DNS_NAME_FORMAT); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11200
From: Thomas Portal <portal.thomas@protonmail.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59891 Signed-off-by: Thomas Portal <portal.thomas@protonmail.com> --- dlls/dnsapi/tests/Makefile.in | 3 +- dlls/dnsapi/tests/service.c | 85 +++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 dlls/dnsapi/tests/service.c diff --git a/dlls/dnsapi/tests/Makefile.in b/dlls/dnsapi/tests/Makefile.in index 15fc3b8e5d9..e4dc9709978 100644 --- a/dlls/dnsapi/tests/Makefile.in +++ b/dlls/dnsapi/tests/Makefile.in @@ -5,4 +5,5 @@ SOURCES = \ cache.c \ name.c \ query.c \ - record.c + record.c \ + service.c diff --git a/dlls/dnsapi/tests/service.c b/dlls/dnsapi/tests/service.c new file mode 100644 index 00000000000..8da0daf3b12 --- /dev/null +++ b/dlls/dnsapi/tests/service.c @@ -0,0 +1,85 @@ +/* + * Tests for dns service functions + * + * Copyright 2026 Thomas Portal + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include <stdio.h> + +#include "windef.h" +#include "winbase.h" +#include "windns.h" + +#include "wine/test.h" + +static PDNS_SERVICE_INSTANCE (WINAPI *pDnsServiceConstructInstance)( PCWSTR, PCWSTR, PIP4_ADDRESS, + PIP6_ADDRESS, WORD, WORD, WORD, DWORD, PCWSTR *, PCWSTR * ); +static VOID (WINAPI *pDnsServiceFreeInstance)( PDNS_SERVICE_INSTANCE ); + +static void test_DnsServiceConstructInstance( void ) +{ + static const WCHAR name[] = L"_test._tcp.local"; + static const WCHAR host[] = L"test.local"; + static const WCHAR *keys[] = { L"txtvers", L"path" }; + static const WCHAR *values[] = { L"1", L"/api" }; + IP4_ADDRESS ip4 = 0x0100007f; /* 127.0.0.1 */ + DNS_SERVICE_INSTANCE *instance; + + instance = pDnsServiceConstructInstance( name, host, &ip4, NULL, 8080, 1, 2, 2, keys, values ); + ok( instance != NULL, "DnsServiceConstructInstance failed\n" ); + if (!instance) return; + + ok( !lstrcmpW( instance->pszInstanceName, name ), "got name %s\n", + wine_dbgstr_w( instance->pszInstanceName ) ); + ok( instance->pszInstanceName != name, "name was not copied\n" ); + ok( !lstrcmpW( instance->pszHostName, host ), "got host %s\n", + wine_dbgstr_w( instance->pszHostName ) ); + ok( instance->ip4Address != NULL, "expected an ip4Address\n" ); + if (instance->ip4Address) + ok( *instance->ip4Address == ip4, "got ip4 %08lx\n", *instance->ip4Address ); + ok( instance->ip6Address == NULL, "expected no ip6Address\n" ); + ok( instance->wPort == 8080, "got port %u\n", instance->wPort ); + ok( instance->wPriority == 1, "got priority %u\n", instance->wPriority ); + ok( instance->wWeight == 2, "got weight %u\n", instance->wWeight ); + ok( instance->dwPropertyCount == 2, "got count %lu\n", instance->dwPropertyCount ); + ok( instance->keys != NULL, "expected keys\n" ); + ok( instance->values != NULL, "expected values\n" ); + if (instance->keys) + ok( !lstrcmpW( instance->keys[0], keys[0] ), "got key %s\n", + wine_dbgstr_w( instance->keys[0] ) ); + if (instance->values) + ok( !lstrcmpW( instance->values[1], values[1] ), "got value %s\n", + wine_dbgstr_w( instance->values[1] ) ); + + pDnsServiceFreeInstance( instance ); +} + +START_TEST(service) +{ + HMODULE dnsapi = GetModuleHandleA( "dnsapi.dll" ); + + pDnsServiceConstructInstance = (void *)GetProcAddress( dnsapi, "DnsServiceConstructInstance" ); + pDnsServiceFreeInstance = (void *)GetProcAddress( dnsapi, "DnsServiceFreeInstance" ); + if (!pDnsServiceConstructInstance || !pDnsServiceFreeInstance) + { + win_skip( "DnsServiceConstructInstance is not available\n" ); + return; + } + + test_DnsServiceConstructInstance(); +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11200
participants (2)
-
Thomas Portal -
Thomas Portal (@OursCodeur)