From: Julian Klemann jklemann@codeweavers.com
Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=53328 --- dlls/windows.devices.enumeration/Makefile.in | 1 + .../event_handlers.c | 109 +++++++ dlls/windows.devices.enumeration/main.c | 275 ++++++++++++++---- dlls/windows.devices.enumeration/private.h | 86 ++++++ 4 files changed, 415 insertions(+), 56 deletions(-) create mode 100644 dlls/windows.devices.enumeration/event_handlers.c create mode 100644 dlls/windows.devices.enumeration/private.h
diff --git a/dlls/windows.devices.enumeration/Makefile.in b/dlls/windows.devices.enumeration/Makefile.in index a2058b3d002..77aa007c0dc 100644 --- a/dlls/windows.devices.enumeration/Makefile.in +++ b/dlls/windows.devices.enumeration/Makefile.in @@ -2,6 +2,7 @@ MODULE = windows.devices.enumeration.dll IMPORTS = combase uuid
C_SRCS = \ + event_handlers.c \ main.c
IDL_SRCS = classes.idl diff --git a/dlls/windows.devices.enumeration/event_handlers.c b/dlls/windows.devices.enumeration/event_handlers.c new file mode 100644 index 00000000000..8451cd72a76 --- /dev/null +++ b/dlls/windows.devices.enumeration/event_handlers.c @@ -0,0 +1,109 @@ +/* WinRT Windows.Devices.Enumeration implementation + * + * Copyright 2022 Bernhard K��lbl + * + * 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 "private.h" + +static CRITICAL_SECTION handlers_cs; +static CRITICAL_SECTION_DEBUG handlers_cs_debug = +{ + 0, 0, &handlers_cs, + { &handlers_cs_debug.ProcessLocksList, &handlers_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": handlers_cs") } +}; +static CRITICAL_SECTION handlers_cs = { &handlers_cs_debug, -1, 0, 0, 0, 0 }; +static EventRegistrationToken next_token = {.value = 1}; + +struct typed_event_handler_entry +{ + struct list entry; + EventRegistrationToken token; + ITypedEventHandler_IInspectable_IInspectable *handler; +}; + +HRESULT typed_event_handlers_append(struct list *list, ITypedEventHandler_IInspectable_IInspectable *handler, EventRegistrationToken *token) +{ + struct typed_event_handler_entry *entry; + + if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY; + ITypedEventHandler_IInspectable_IInspectable_AddRef((entry->handler = handler)); + + EnterCriticalSection(&handlers_cs); + + *token = entry->token = next_token; + next_token.value++; + list_add_tail(list, &entry->entry); + + LeaveCriticalSection(&handlers_cs); + + return S_OK; +} + +HRESULT typed_event_handlers_remove(struct list *list, EventRegistrationToken *token) +{ + struct typed_event_handler_entry *entry; + BOOL found = FALSE; + + EnterCriticalSection(&handlers_cs); + + LIST_FOR_EACH_ENTRY(entry, list, struct typed_event_handler_entry, entry) + if ((found = !memcmp(&entry->token, token, sizeof(*token)))) break; + if (found) list_remove(&entry->entry); + + LeaveCriticalSection(&handlers_cs); + + if (found) + { + ITypedEventHandler_IInspectable_IInspectable_Release(entry->handler); + free(entry); + } + + return S_OK; +} + +HRESULT typed_event_handlers_notify(struct list *list, IInspectable *sender, IInspectable *args) +{ + struct typed_event_handler_entry *entry; + + EnterCriticalSection(&handlers_cs); + + LIST_FOR_EACH_ENTRY(entry, list, struct typed_event_handler_entry, entry) + ITypedEventHandler_IInspectable_IInspectable_Invoke(entry->handler, sender, args); + + LeaveCriticalSection(&handlers_cs); + + return S_OK; +} + +HRESULT typed_event_handlers_clear(struct list *list) +{ + struct typed_event_handler_entry *entry, *entry_cursor2; + + EnterCriticalSection(&handlers_cs); + + LIST_FOR_EACH_ENTRY_SAFE(entry, entry_cursor2, list, struct typed_event_handler_entry, entry) + { + list_remove(&entry->entry); + ITypedEventHandler_IInspectable_IInspectable_Release(entry->handler); + free(entry); + } + + LeaveCriticalSection(&handlers_cs); + + return S_OK; +} diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index b6cab670bce..3b3719756cc 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -18,63 +18,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include <stdarg.h> +#include "initguid.h" +#include "private.h"
-#define COBJMACROS -#include "windef.h" -#include "winbase.h" -#include "winstring.h" #include "wine/debug.h" -#include "objbase.h" - -#include "initguid.h" -#include "activation.h" - -#define WIDL_using_Windows_Foundation -#define WIDL_using_Windows_Foundation_Collections -#include "windows.foundation.h" -#define WIDL_using_Windows_Devices_Enumeration -#include "windows.devices.enumeration.h" - -#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ - static inline impl_type *impl_from( iface_type *iface ) \ - { \ - return CONTAINING_RECORD( iface, impl_type, iface_mem ); \ - } \ - static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \ - { \ - impl_type *impl = impl_from( iface ); \ - return IInspectable_QueryInterface( (IInspectable *)(expr), iid, out ); \ - } \ - static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \ - { \ - impl_type *impl = impl_from( iface ); \ - return IInspectable_AddRef( (IInspectable *)(expr) ); \ - } \ - static ULONG WINAPI pfx##_Release( iface_type *iface ) \ - { \ - impl_type *impl = impl_from( iface ); \ - return IInspectable_Release( (IInspectable *)(expr) ); \ - } \ - static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \ - { \ - impl_type *impl = impl_from( iface ); \ - return IInspectable_GetIids( (IInspectable *)(expr), iid_count, iids ); \ - } \ - static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \ - { \ - impl_type *impl = impl_from( iface ); \ - return IInspectable_GetRuntimeClassName( (IInspectable *)(expr), class_name ); \ - } \ - static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \ - { \ - impl_type *impl = impl_from( iface ); \ - return IInspectable_GetTrustLevel( (IInspectable *)(expr), trust_level ); \ - } -#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface ) \ - DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface ) -#define DEFINE_IINSPECTABLE_OUTER( pfx, iface_type, impl_type, outer_iface ) \ - DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, impl->outer_iface )
WINE_DEFAULT_DEBUG_CHANNEL(enumeration);
@@ -87,6 +34,208 @@ static const char *debugstr_hstring(HSTRING hstr) return wine_dbgstr_wn(str, len); }
+struct device_watcher +{ + IDeviceWatcher IDeviceWatcher_iface; + LONG ref; + + struct list stopped_handlers; +}; + +static inline struct device_watcher *impl_from_IDeviceWatcher(IDeviceWatcher *iface) +{ + return CONTAINING_RECORD(iface, struct device_watcher, IDeviceWatcher_iface); +} + +static HRESULT WINAPI device_watcher_QueryInterface( + IDeviceWatcher *iface, REFIID iid, void **out) +{ + struct device_watcher *impl = impl_from_IDeviceWatcher(iface); + + TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IDeviceWatcher)) + { + IInspectable_AddRef((*out = &impl->IDeviceWatcher_iface)); + return S_OK; + } + + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI device_watcher_AddRef( + IDeviceWatcher *iface) +{ + struct device_watcher *impl = impl_from_IDeviceWatcher(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +static ULONG WINAPI device_watcher_Release( + IDeviceWatcher *iface) +{ + struct device_watcher *impl = impl_from_IDeviceWatcher(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + + if (!ref) + { + typed_event_handlers_clear(&impl->stopped_handlers); + free(impl); + } + + return ref; +} + +static HRESULT WINAPI device_watcher_GetIids( + IDeviceWatcher *iface, ULONG *iid_count, IID **iids) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT WINAPI device_watcher_GetRuntimeClassName( + IDeviceWatcher *iface, HSTRING *class_name) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI device_watcher_GetTrustLevel( + IDeviceWatcher *iface, TrustLevel *trust_level) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT WINAPI device_watcher_add_Added( + IDeviceWatcher *iface, ITypedEventHandler_DeviceWatcher_DeviceInformation *handler, + EventRegistrationToken *token) +{ + FIXME("iface %p, handler %p, token %p stub!\n", iface, handler, token); + return S_OK; +} + +static HRESULT WINAPI device_watcher_remove_Added(IDeviceWatcher *iface, EventRegistrationToken token) +{ + FIXME("iface %p, token %#I64x stub!\n", iface, token.value); + return E_NOTIMPL; +} + +static HRESULT WINAPI device_watcher_add_Updated( + IDeviceWatcher *iface, ITypedEventHandler_DeviceWatcher_DeviceInformationUpdate *handler, + EventRegistrationToken *token) +{ + FIXME("iface %p, handler %p, token %p stub!\n", iface, handler, token); + return S_OK; +} + +static HRESULT WINAPI device_watcher_remove_Updated(IDeviceWatcher *iface, EventRegistrationToken token) +{ + FIXME("iface %p, token %#I64x stub!\n", iface, token.value); + return E_NOTIMPL; +} + +static HRESULT WINAPI device_watcher_add_Removed( + IDeviceWatcher *iface, ITypedEventHandler_DeviceWatcher_DeviceInformationUpdate *handler, + EventRegistrationToken *token) +{ + FIXME("iface %p, handler %p, token %p stub!\n", iface, handler, token); + return E_NOTIMPL; +} + +static HRESULT WINAPI device_watcher_remove_Removed(IDeviceWatcher *iface, EventRegistrationToken token) +{ + FIXME("iface %p, token %#I64x stub!\n", iface, token.value); + return E_NOTIMPL; +} + +static HRESULT WINAPI device_watcher_add_EnumerationCompleted( + IDeviceWatcher *iface, ITypedEventHandler_DeviceWatcher_IInspectable *handler, EventRegistrationToken *token) +{ + FIXME("iface %p, handler %p, token %p stub!\n", iface, handler, token); + return E_NOTIMPL; +} + +static HRESULT WINAPI device_watcher_remove_EnumerationCompleted( + IDeviceWatcher *iface, EventRegistrationToken token) +{ + FIXME("iface %p, token %#I64x stub!\n", iface, token.value); + return E_NOTIMPL; +} + +static HRESULT WINAPI device_watcher_add_Stopped( + IDeviceWatcher *iface, ITypedEventHandler_DeviceWatcher_IInspectable *handler, EventRegistrationToken *token) +{ + struct device_watcher *impl = impl_from_IDeviceWatcher(iface); + + TRACE("iface %p, handler %p, token %p.\n", iface, handler, token); + return typed_event_handlers_append(&impl->stopped_handlers, (ITypedEventHandler_IInspectable_IInspectable *)handler, token); +} + +static HRESULT WINAPI device_watcher_remove_Stopped(IDeviceWatcher *iface, EventRegistrationToken token) +{ + struct device_watcher *impl = impl_from_IDeviceWatcher(iface); + + TRACE("iface %p, token %#I64x.\n", iface, token.value); + return typed_event_handlers_remove(&impl->stopped_handlers, &token); +} + +static HRESULT WINAPI device_watcher_Status(IDeviceWatcher *iface, DeviceWatcherStatus *status) +{ + FIXME("iface %p, status %p stub!\n", iface, status); + return E_NOTIMPL; +} + +static HRESULT WINAPI device_watcher_Start(IDeviceWatcher *iface) +{ + FIXME("iface %p stub!\n", iface); + return S_OK; +} + +static HRESULT WINAPI device_watcher_Stop(IDeviceWatcher *iface) +{ + struct device_watcher *impl = impl_from_IDeviceWatcher(iface); + HRESULT hr; + + FIXME("iface %p stub!\n", iface); + + IDeviceWatcher_AddRef(&impl->IDeviceWatcher_iface); + hr = typed_event_handlers_notify(&impl->stopped_handlers, (IInspectable *)iface, NULL); + IDeviceWatcher_Release(&impl->IDeviceWatcher_iface); + return hr; +} + +static const struct IDeviceWatcherVtbl device_watcher_vtbl = +{ + device_watcher_QueryInterface, + device_watcher_AddRef, + device_watcher_Release, + /* IInspectable methods */ + device_watcher_GetIids, + device_watcher_GetRuntimeClassName, + device_watcher_GetTrustLevel, + /* IDeviceWatcher methods */ + device_watcher_add_Added, + device_watcher_remove_Added, + device_watcher_add_Updated, + device_watcher_remove_Updated, + device_watcher_add_Removed, + device_watcher_remove_Removed, + device_watcher_add_EnumerationCompleted, + device_watcher_remove_EnumerationCompleted, + device_watcher_add_Stopped, + device_watcher_remove_Stopped, + device_watcher_Status, + device_watcher_Start, + device_watcher_Stop, +}; + struct windows_devices_enumeration { IActivationFactory IActivationFactory_iface; @@ -215,9 +364,23 @@ static HRESULT WINAPI device_statics2_CreateWatcher( IDeviceInformationStatics2 *iface, HSTRING filter, IIterable_HSTRING *additionalProperties, DeviceInformationKind kind, IDeviceWatcher **watcher) { + struct device_watcher *this; + HRESULT hr; + FIXME("iface %p, filter %s, additionalProperties %p, kind %u, watcher %p stub!\n", iface, debugstr_hstring(filter), additionalProperties, kind, watcher); - return E_NOTIMPL; + + if (!(this = malloc(sizeof(*this)))) + return E_OUTOFMEMORY; + + this->IDeviceWatcher_iface.lpVtbl = &device_watcher_vtbl; + this->ref = 1; + + list_init(&this->stopped_handlers); + + hr = IDeviceWatcher_QueryInterface(&this->IDeviceWatcher_iface, &IID_IDeviceWatcher, (void **)watcher); + IDeviceWatcher_Release(&this->IDeviceWatcher_iface); + return hr; }
static const struct IDeviceInformationStatics2Vtbl device_statics2_vtbl = diff --git a/dlls/windows.devices.enumeration/private.h b/dlls/windows.devices.enumeration/private.h new file mode 100644 index 00000000000..13ac54723cd --- /dev/null +++ b/dlls/windows.devices.enumeration/private.h @@ -0,0 +1,86 @@ +/* WinRT Windows.Devices.Enumeration implementation + * + * Copyright 2021 Gijs Vermeulen + * + * 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 + */ + +#ifndef __WINE_WINDOWS_DEVICES_ENUMERATION_PRIVATE_H +#define __WINE_WINDOWS_DEVICES_ENUMERATION_PRIVATE_H + +#include <stdarg.h> + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winstring.h" +#include "objbase.h" + +#include "activation.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#define WIDL_using_Windows_Devices_Enumeration +#include "windows.devices.enumeration.h" + +#include "wine/list.h" + +HRESULT typed_event_handlers_append(struct list *list, ITypedEventHandler_IInspectable_IInspectable *handler, EventRegistrationToken *token); +HRESULT typed_event_handlers_remove(struct list *list, EventRegistrationToken *token); +HRESULT typed_event_handlers_notify(struct list *list, IInspectable *sender, IInspectable *args); +HRESULT typed_event_handlers_clear(struct list *list); + +#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ + static inline impl_type *impl_from( iface_type *iface ) \ + { \ + return CONTAINING_RECORD( iface, impl_type, iface_mem ); \ + } \ + static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_QueryInterface( (IInspectable *)(expr), iid, out ); \ + } \ + static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_AddRef( (IInspectable *)(expr) ); \ + } \ + static ULONG WINAPI pfx##_Release( iface_type *iface ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_Release( (IInspectable *)(expr) ); \ + } \ + static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetIids( (IInspectable *)(expr), iid_count, iids ); \ + } \ + static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetRuntimeClassName( (IInspectable *)(expr), class_name ); \ + } \ + static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetTrustLevel( (IInspectable *)(expr), trust_level ); \ + } +#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface ) \ + DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface ) +#define DEFINE_IINSPECTABLE_OUTER( pfx, iface_type, impl_type, outer_iface ) \ + DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, impl->outer_iface ) + +#endif