[PATCH v3 0/8] MR10078: cfgmgr32: Implement CM_Enumerate_Classes(_Ex).
-- v3: setupapi: Forward CM_Enumerate_Classes(_Ex) to cfgmgr32. cfgmgr32: Implement CM_Enumerate_Classes(_Ex). cfgmgr32: Cache some common root registry keys. setupapi: Forward CM_Open_Class_Key(_Ex)(A|W) to cfgmgr32. cfgmgr32: Implement CM_Open_Class_Key(_Ex)(A|W). setupapi: Forward CM_Get_Class_Key_Name(_Ex)(A|W) to cfgmgr32. cfgmgr32: Implement CM_Get_Class_Key_Name(_Ex)(A|W). cfgmgr32: Split sources to separate files. https://gitlab.winehq.org/wine/wine/-/merge_requests/10078
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/Makefile.in | 4 +- dlls/cfgmgr32/cfgmgr32.c | 106 ++++++++++ dlls/cfgmgr32/cfgmgr32_private.h | 51 +++++ dlls/cfgmgr32/{main.c => devobject.c} | 293 +------------------------- dlls/cfgmgr32/notification.c | 203 ++++++++++++++++++ 5 files changed, 364 insertions(+), 293 deletions(-) create mode 100644 dlls/cfgmgr32/cfgmgr32.c create mode 100644 dlls/cfgmgr32/cfgmgr32_private.h rename dlls/cfgmgr32/{main.c => devobject.c} (80%) create mode 100644 dlls/cfgmgr32/notification.c diff --git a/dlls/cfgmgr32/Makefile.in b/dlls/cfgmgr32/Makefile.in index fd819760e6f..1c04637124f 100644 --- a/dlls/cfgmgr32/Makefile.in +++ b/dlls/cfgmgr32/Makefile.in @@ -3,4 +3,6 @@ IMPORTLIB = cfgmgr32 IMPORTS = advapi32 rpcrt4 sechost setupapi SOURCES = \ - main.c + cfgmgr32.c \ + devobject.c \ + notification.c diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c new file mode 100644 index 00000000000..7362069490a --- /dev/null +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2023 Mohamad Al-Jaf + * Copyright (C) 2025 Vibhav Pant + * + * 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 "cfgmgr32_private.h" +#include "initguid.h" +#include "devpkey.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +/*********************************************************************** + * CM_MapCrToWin32Err (cfgmgr32.@) + */ +DWORD WINAPI CM_MapCrToWin32Err( CONFIGRET code, DWORD default_error ) +{ + TRACE( "code: %#lx, default_error: %ld\n", code, default_error ); + + switch (code) + { + case CR_SUCCESS: return ERROR_SUCCESS; + case CR_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY; + case CR_INVALID_POINTER: return ERROR_INVALID_USER_BUFFER; + case CR_INVALID_FLAG: return ERROR_INVALID_FLAGS; + case CR_INVALID_DEVNODE: + case CR_INVALID_DEVICE_ID: + case CR_INVALID_MACHINENAME: + case CR_INVALID_PROPERTY: + case CR_INVALID_REFERENCE_STRING: return ERROR_INVALID_DATA; + case CR_NO_SUCH_DEVNODE: + case CR_NO_SUCH_VALUE: + case CR_NO_SUCH_DEVICE_INTERFACE: return ERROR_NOT_FOUND; + case CR_ALREADY_SUCH_DEVNODE: return ERROR_ALREADY_EXISTS; + case CR_BUFFER_SMALL: return ERROR_INSUFFICIENT_BUFFER; + case CR_NO_REGISTRY_HANDLE: return ERROR_INVALID_HANDLE; + case CR_REGISTRY_ERROR: return ERROR_REGISTRY_CORRUPT; + case CR_NO_SUCH_REGISTRY_KEY: return ERROR_FILE_NOT_FOUND; + case CR_REMOTE_COMM_FAILURE: + case CR_MACHINE_UNAVAILABLE: + case CR_NO_CM_SERVICES: return ERROR_SERVICE_NOT_ACTIVE; + case CR_ACCESS_DENIED: return ERROR_ACCESS_DENIED; + case CR_CALL_NOT_IMPLEMENTED: return ERROR_CALL_NOT_IMPLEMENTED; + } + + return default_error; +} + +/*********************************************************************** + * CM_Get_Device_Interface_PropertyW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_PropertyW( LPCWSTR device_interface, const DEVPROPKEY *property_key, + DEVPROPTYPE *property_type, BYTE *property_buffer, + ULONG *property_buffer_size, ULONG flags ) +{ + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + HDEVINFO set; + DWORD err; + BOOL ret; + + TRACE( "%s %p %p %p %p %ld.\n", debugstr_w(device_interface), property_key, property_type, property_buffer, + property_buffer_size, flags); + + if (!property_key) return CR_FAILURE; + if (!device_interface || !property_type || !property_buffer_size) return CR_INVALID_POINTER; + if (*property_buffer_size && !property_buffer) return CR_INVALID_POINTER; + if (flags) return CR_INVALID_FLAG; + + set = SetupDiCreateDeviceInfoListExW( NULL, NULL, NULL, NULL ); + if (set == INVALID_HANDLE_VALUE) return CR_OUT_OF_MEMORY; + if (!SetupDiOpenDeviceInterfaceW( set, device_interface, 0, &iface )) + { + SetupDiDestroyDeviceInfoList( set ); + TRACE( "No interface %s, err %lu.\n", debugstr_w( device_interface ), GetLastError()); + return CR_NO_SUCH_DEVICE_INTERFACE; + } + + ret = SetupDiGetDeviceInterfacePropertyW( set, &iface, property_key, property_type, property_buffer, + *property_buffer_size, property_buffer_size, 0 ); + err = ret ? 0 : GetLastError(); + SetupDiDestroyDeviceInfoList( set ); + switch (err) + { + case ERROR_SUCCESS: + return CR_SUCCESS; + case ERROR_INSUFFICIENT_BUFFER: + return CR_BUFFER_SMALL; + case ERROR_NOT_FOUND: + return CR_NO_SUCH_VALUE; + default: + return CR_FAILURE; + } +} diff --git a/dlls/cfgmgr32/cfgmgr32_private.h b/dlls/cfgmgr32/cfgmgr32_private.h new file mode 100644 index 00000000000..0aad9a3f247 --- /dev/null +++ b/dlls/cfgmgr32/cfgmgr32_private.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 Mohamad Al-Jaf + * Copyright (C) 2025 Vibhav Pant + * + * 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 <stddef.h> +#include <stdarg.h> +#include <assert.h> + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" +#include "winuser.h" + +#include "cfgmgr32.h" +#include "setupapi.h" +#include "dbt.h" +#include "devfiltertypes.h" +#include "devquery.h" + +#include "wine/plugplay.h" +#include "wine/rbtree.h" +#include "wine/debug.h" + +static inline const char *debugstr_DEVPROPKEY( const DEVPROPKEY *key ) +{ + if (!key) return "(null)"; + return wine_dbg_sprintf( "{%s, %04lx}", debugstr_guid( &key->fmtid ), key->pid ); +} + +static inline const char *debugstr_DEVPROPCOMPKEY( const DEVPROPCOMPKEY *key ) +{ + if (!key) return "(null)"; + return wine_dbg_sprintf( "{%s, %d, %s}", debugstr_DEVPROPKEY( &key->Key ), key->Store, + debugstr_w( key->LocaleName ) ); +} diff --git a/dlls/cfgmgr32/main.c b/dlls/cfgmgr32/devobject.c similarity index 80% rename from dlls/cfgmgr32/main.c rename to dlls/cfgmgr32/devobject.c index 8ae08e7c7e8..c4934f6590a 100644 --- a/dlls/cfgmgr32/main.c +++ b/dlls/cfgmgr32/devobject.c @@ -17,289 +17,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include <assert.h> - -#include "wine/debug.h" -#include "wine/rbtree.h" -#include "winreg.h" -#include "winternl.h" -#include "cfgmgr32.h" -#include "winuser.h" -#include "dbt.h" -#include "wine/plugplay.h" -#include "setupapi.h" -#include "devfiltertypes.h" -#include "devquery.h" - -#include "initguid.h" +#include "cfgmgr32_private.h" #include "devpkey.h" WINE_DEFAULT_DEBUG_CHANNEL(setupapi); -/*********************************************************************** - * CM_MapCrToWin32Err (cfgmgr32.@) - */ -DWORD WINAPI CM_MapCrToWin32Err( CONFIGRET code, DWORD default_error ) -{ - TRACE( "code: %#lx, default_error: %ld\n", code, default_error ); - - switch (code) - { - case CR_SUCCESS: return ERROR_SUCCESS; - case CR_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY; - case CR_INVALID_POINTER: return ERROR_INVALID_USER_BUFFER; - case CR_INVALID_FLAG: return ERROR_INVALID_FLAGS; - case CR_INVALID_DEVNODE: - case CR_INVALID_DEVICE_ID: - case CR_INVALID_MACHINENAME: - case CR_INVALID_PROPERTY: - case CR_INVALID_REFERENCE_STRING: return ERROR_INVALID_DATA; - case CR_NO_SUCH_DEVNODE: - case CR_NO_SUCH_VALUE: - case CR_NO_SUCH_DEVICE_INTERFACE: return ERROR_NOT_FOUND; - case CR_ALREADY_SUCH_DEVNODE: return ERROR_ALREADY_EXISTS; - case CR_BUFFER_SMALL: return ERROR_INSUFFICIENT_BUFFER; - case CR_NO_REGISTRY_HANDLE: return ERROR_INVALID_HANDLE; - case CR_REGISTRY_ERROR: return ERROR_REGISTRY_CORRUPT; - case CR_NO_SUCH_REGISTRY_KEY: return ERROR_FILE_NOT_FOUND; - case CR_REMOTE_COMM_FAILURE: - case CR_MACHINE_UNAVAILABLE: - case CR_NO_CM_SERVICES: return ERROR_SERVICE_NOT_ACTIVE; - case CR_ACCESS_DENIED: return ERROR_ACCESS_DENIED; - case CR_CALL_NOT_IMPLEMENTED: return ERROR_CALL_NOT_IMPLEMENTED; - } - - return default_error; -} - -struct cm_notify_context -{ - HDEVNOTIFY notify; - void *user_data; - PCM_NOTIFY_CALLBACK callback; -}; - -CALLBACK DWORD devnotify_callback( HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header ) -{ - struct cm_notify_context *ctx = handle; - CM_NOTIFY_EVENT_DATA *event_data; - CM_NOTIFY_ACTION action; - DWORD size, ret; - - TRACE( "(%p, %#lx, %p)\n", handle, flags, header ); - - switch (flags) - { - case DBT_DEVICEARRIVAL: - action = CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL; - break; - case DBT_DEVICEREMOVECOMPLETE: - FIXME( "CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE not implemented\n" ); - action = CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL; - break; - case DBT_CUSTOMEVENT: - action = CM_NOTIFY_ACTION_DEVICECUSTOMEVENT; - break; - default: - FIXME( "Unexpected flags value: %#lx\n", flags ); - return 0; - } - - switch (header->dbch_devicetype) - { - case DBT_DEVTYP_DEVICEINTERFACE: - { - const DEV_BROADCAST_DEVICEINTERFACE_W *iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)header; - UINT data_size = wcslen( iface->dbcc_name ) + 1; - - size = offsetof( CM_NOTIFY_EVENT_DATA, u.DeviceInterface.SymbolicLink[data_size] ); - if (!(event_data = calloc( 1, size ))) return 0; - - event_data->FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE; - event_data->u.DeviceInterface.ClassGuid = iface->dbcc_classguid; - memcpy( event_data->u.DeviceInterface.SymbolicLink, iface->dbcc_name, data_size * sizeof(WCHAR) ); - break; - } - case DBT_DEVTYP_HANDLE: - { - const DEV_BROADCAST_HANDLE *handle = (DEV_BROADCAST_HANDLE *)header; - UINT data_size = handle->dbch_size - 2 * sizeof(WCHAR) - offsetof( DEV_BROADCAST_HANDLE, dbch_data ); - - size = offsetof( CM_NOTIFY_EVENT_DATA, u.DeviceHandle.Data[data_size] ); - if (!(event_data = calloc( 1, size ))) return 0; - - event_data->FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE; - event_data->u.DeviceHandle.EventGuid = handle->dbch_eventguid; - event_data->u.DeviceHandle.NameOffset = handle->dbch_nameoffset; - event_data->u.DeviceHandle.DataSize = data_size; - memcpy( event_data->u.DeviceHandle.Data, handle->dbch_data, data_size ); - break; - } - default: - FIXME( "Unexpected devicetype value: %#lx\n", header->dbch_devicetype ); - return 0; - } - - ret = ctx->callback( ctx, ctx->user_data, action, event_data, size ); - free( event_data ); - return ret; -} - -static const char *debugstr_CM_NOTIFY_FILTER( const CM_NOTIFY_FILTER *filter ) -{ - if (!filter) return "(null)"; - switch (filter->FilterType) - { - case CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE: - return wine_dbg_sprintf( "{%#lx %lx CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE %lu {{%s}}}", filter->cbSize, - filter->Flags, filter->Reserved, - debugstr_guid( &filter->u.DeviceInterface.ClassGuid ) ); - case CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE: - return wine_dbg_sprintf( "{%#lx %lx CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE %lu {{%p}}}", filter->cbSize, - filter->Flags, filter->Reserved, filter->u.DeviceHandle.hTarget ); - case CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE: - return wine_dbg_sprintf( "{%#lx %lx CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE %lu {{%s}}}", filter->cbSize, - filter->Flags, filter->Reserved, debugstr_w( filter->u.DeviceInstance.InstanceId ) ); - default: - return wine_dbg_sprintf( "{%#lx %lx (unknown FilterType %d) %lu}", filter->cbSize, filter->Flags, - filter->FilterType, filter->Reserved ); - } -} - -static CONFIGRET create_notify_context( const CM_NOTIFY_FILTER *filter, HCMNOTIFICATION *notify_handle, - PCM_NOTIFY_CALLBACK callback, void *user_data ) -{ - union - { - DEV_BROADCAST_HDR header; - DEV_BROADCAST_DEVICEINTERFACE_W iface; - DEV_BROADCAST_HANDLE handle; - } notify_filter = {0}; - struct cm_notify_context *ctx; - static const GUID GUID_NULL; - - switch (filter->FilterType) - { - case CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE: - notify_filter.iface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; - if (filter->Flags & CM_NOTIFY_FILTER_FLAG_ALL_INTERFACE_CLASSES) - { - if (!IsEqualGUID( &filter->u.DeviceInterface.ClassGuid, &GUID_NULL )) return CR_INVALID_DATA; - notify_filter.iface.dbcc_size = offsetof( DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_classguid ); - } - else - { - notify_filter.iface.dbcc_size = offsetof( DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_name ); - notify_filter.iface.dbcc_classguid = filter->u.DeviceInterface.ClassGuid; - } - break; - case CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE: - notify_filter.handle.dbch_devicetype = DBT_DEVTYP_HANDLE; - notify_filter.handle.dbch_size = sizeof(notify_filter.handle); - notify_filter.handle.dbch_handle = filter->u.DeviceHandle.hTarget; - break; - case CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE: - FIXME( "CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE is not supported!\n" ); - return CR_CALL_NOT_IMPLEMENTED; - default: - return CR_INVALID_DATA; - } - - if (!(ctx = calloc( 1, sizeof(*ctx) ))) return CR_OUT_OF_MEMORY; - - ctx->user_data = user_data; - ctx->callback = callback; - if (!(ctx->notify = I_ScRegisterDeviceNotification( ctx, ¬ify_filter.header, devnotify_callback ))) - { - free( ctx ); - switch (GetLastError()) - { - case ERROR_NOT_ENOUGH_MEMORY: return CR_OUT_OF_MEMORY; - case ERROR_INVALID_PARAMETER: return CR_INVALID_DATA; - default: return CR_FAILURE; - } - } - *notify_handle = ctx; - return CR_SUCCESS; -} - -/*********************************************************************** - * CM_Register_Notification (cfgmgr32.@) - */ -CONFIGRET WINAPI CM_Register_Notification( CM_NOTIFY_FILTER *filter, void *context, - PCM_NOTIFY_CALLBACK callback, HCMNOTIFICATION *notify_context ) -{ - TRACE( "(%s %p %p %p)\n", debugstr_CM_NOTIFY_FILTER( filter ), context, callback, notify_context ); - - if (!notify_context) return CR_FAILURE; - if (!filter || !callback || filter->cbSize != sizeof(*filter)) return CR_INVALID_DATA; - - return create_notify_context( filter, notify_context, callback, context ); -} - -/*********************************************************************** - * CM_Unregister_Notification (cfgmgr32.@) - */ -CONFIGRET WINAPI CM_Unregister_Notification( HCMNOTIFICATION notify ) -{ - struct cm_notify_context *ctx = notify; - - TRACE( "(%p)\n", notify ); - - if (!notify) return CR_INVALID_DATA; - - I_ScUnregisterDeviceNotification( ctx->notify ); - free( ctx ); - - return CR_SUCCESS; -} - -/*********************************************************************** - * CM_Get_Device_Interface_PropertyW (cfgmgr32.@) - */ -CONFIGRET WINAPI CM_Get_Device_Interface_PropertyW( LPCWSTR device_interface, const DEVPROPKEY *property_key, - DEVPROPTYPE *property_type, BYTE *property_buffer, - ULONG *property_buffer_size, ULONG flags ) -{ - SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; - HDEVINFO set; - DWORD err; - BOOL ret; - - TRACE( "%s %p %p %p %p %ld.\n", debugstr_w(device_interface), property_key, property_type, property_buffer, - property_buffer_size, flags); - - if (!property_key) return CR_FAILURE; - if (!device_interface || !property_type || !property_buffer_size) return CR_INVALID_POINTER; - if (*property_buffer_size && !property_buffer) return CR_INVALID_POINTER; - if (flags) return CR_INVALID_FLAG; - - set = SetupDiCreateDeviceInfoListExW( NULL, NULL, NULL, NULL ); - if (set == INVALID_HANDLE_VALUE) return CR_OUT_OF_MEMORY; - if (!SetupDiOpenDeviceInterfaceW( set, device_interface, 0, &iface )) - { - SetupDiDestroyDeviceInfoList( set ); - TRACE( "No interface %s, err %lu.\n", debugstr_w( device_interface ), GetLastError()); - return CR_NO_SUCH_DEVICE_INTERFACE; - } - - ret = SetupDiGetDeviceInterfacePropertyW( set, &iface, property_key, property_type, property_buffer, - *property_buffer_size, property_buffer_size, 0 ); - err = ret ? 0 : GetLastError(); - SetupDiDestroyDeviceInfoList( set ); - switch (err) - { - case ERROR_SUCCESS: - return CR_SUCCESS; - case ERROR_INSUFFICIENT_BUFFER: - return CR_BUFFER_SMALL; - case ERROR_NOT_FOUND: - return CR_NO_SUCH_VALUE; - default: - return CR_FAILURE; - } -} - static BOOL dev_properties_append( DEVPROPERTY **properties, ULONG *props_len, const DEVPROPKEY *key, DEVPROPTYPE type, ULONG buf_size, void *buf ) { @@ -321,19 +43,6 @@ static BOOL dev_properties_append( DEVPROPERTY **properties, ULONG *props_len, c return TRUE; } -static const char *debugstr_DEVPROPKEY( const DEVPROPKEY *key ) -{ - if (!key) return "(null)"; - return wine_dbg_sprintf( "{%s, %04lx}", debugstr_guid( &key->fmtid ), key->pid ); -} - -static const char *debugstr_DEVPROPCOMPKEY( const DEVPROPCOMPKEY *key ) -{ - if (!key) return "(null)"; - return wine_dbg_sprintf( "{%s, %d, %s}", debugstr_DEVPROPKEY( &key->Key ), key->Store, - debugstr_w( key->LocaleName ) ); -} - static const char *debugstr_DEV_OBJECT( const DEV_OBJECT *obj ) { if (!obj) return "(null)"; diff --git a/dlls/cfgmgr32/notification.c b/dlls/cfgmgr32/notification.c new file mode 100644 index 00000000000..e0b3893430f --- /dev/null +++ b/dlls/cfgmgr32/notification.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2023 Mohamad Al-Jaf + * Copyright (C) 2025 Vibhav Pant + * + * 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 "cfgmgr32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +static const char *debugstr_CM_NOTIFY_FILTER( const CM_NOTIFY_FILTER *filter ) +{ + if (!filter) return "(null)"; + switch (filter->FilterType) + { + case CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE: + return wine_dbg_sprintf( "{%#lx %lx CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE %lu {{%s}}}", filter->cbSize, + filter->Flags, filter->Reserved, debugstr_guid( &filter->u.DeviceInterface.ClassGuid ) ); + case CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE: + return wine_dbg_sprintf( "{%#lx %lx CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE %lu {{%p}}}", filter->cbSize, + filter->Flags, filter->Reserved, filter->u.DeviceHandle.hTarget ); + case CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE: + return wine_dbg_sprintf( "{%#lx %lx CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE %lu {{%s}}}", filter->cbSize, + filter->Flags, filter->Reserved, debugstr_w( filter->u.DeviceInstance.InstanceId ) ); + default: + return wine_dbg_sprintf( "{%#lx %lx (unknown FilterType %d) %lu}", filter->cbSize, filter->Flags, + filter->FilterType, filter->Reserved ); + } +} + +struct cm_notify_context +{ + HDEVNOTIFY notify; + void *user_data; + PCM_NOTIFY_CALLBACK callback; +}; + +CALLBACK DWORD devnotify_callback( HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header ) +{ + struct cm_notify_context *ctx = handle; + CM_NOTIFY_EVENT_DATA *event_data; + CM_NOTIFY_ACTION action; + DWORD size, ret; + + TRACE( "(%p, %#lx, %p)\n", handle, flags, header ); + + switch (flags) + { + case DBT_DEVICEARRIVAL: + action = CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL; + break; + case DBT_DEVICEREMOVECOMPLETE: + FIXME( "CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE not implemented\n" ); + action = CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL; + break; + case DBT_CUSTOMEVENT: + action = CM_NOTIFY_ACTION_DEVICECUSTOMEVENT; + break; + default: + FIXME( "Unexpected flags value: %#lx\n", flags ); + return 0; + } + + switch (header->dbch_devicetype) + { + case DBT_DEVTYP_DEVICEINTERFACE: + { + const DEV_BROADCAST_DEVICEINTERFACE_W *iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)header; + UINT data_size = wcslen( iface->dbcc_name ) + 1; + + size = offsetof( CM_NOTIFY_EVENT_DATA, u.DeviceInterface.SymbolicLink[data_size] ); + if (!(event_data = calloc( 1, size ))) return 0; + + event_data->FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE; + event_data->u.DeviceInterface.ClassGuid = iface->dbcc_classguid; + memcpy( event_data->u.DeviceInterface.SymbolicLink, iface->dbcc_name, data_size * sizeof(WCHAR) ); + break; + } + case DBT_DEVTYP_HANDLE: + { + const DEV_BROADCAST_HANDLE *handle = (DEV_BROADCAST_HANDLE *)header; + UINT data_size = handle->dbch_size - 2 * sizeof(WCHAR) - offsetof( DEV_BROADCAST_HANDLE, dbch_data ); + + size = offsetof( CM_NOTIFY_EVENT_DATA, u.DeviceHandle.Data[data_size] ); + if (!(event_data = calloc( 1, size ))) return 0; + + event_data->FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE; + event_data->u.DeviceHandle.EventGuid = handle->dbch_eventguid; + event_data->u.DeviceHandle.NameOffset = handle->dbch_nameoffset; + event_data->u.DeviceHandle.DataSize = data_size; + memcpy( event_data->u.DeviceHandle.Data, handle->dbch_data, data_size ); + break; + } + default: + FIXME( "Unexpected devicetype value: %#lx\n", header->dbch_devicetype ); + return 0; + } + + ret = ctx->callback( ctx, ctx->user_data, action, event_data, size ); + free( event_data ); + return ret; +} + +static CONFIGRET create_notify_context( const CM_NOTIFY_FILTER *filter, HCMNOTIFICATION *notify_handle, + PCM_NOTIFY_CALLBACK callback, void *user_data ) +{ + union + { + DEV_BROADCAST_HDR header; + DEV_BROADCAST_DEVICEINTERFACE_W iface; + DEV_BROADCAST_HANDLE handle; + } notify_filter = {0}; + struct cm_notify_context *ctx; + static const GUID GUID_NULL; + + switch (filter->FilterType) + { + case CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE: + notify_filter.iface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + if (filter->Flags & CM_NOTIFY_FILTER_FLAG_ALL_INTERFACE_CLASSES) + { + if (!IsEqualGUID( &filter->u.DeviceInterface.ClassGuid, &GUID_NULL )) return CR_INVALID_DATA; + notify_filter.iface.dbcc_size = offsetof( DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_classguid ); + } + else + { + notify_filter.iface.dbcc_size = offsetof( DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_name ); + notify_filter.iface.dbcc_classguid = filter->u.DeviceInterface.ClassGuid; + } + break; + case CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE: + notify_filter.handle.dbch_devicetype = DBT_DEVTYP_HANDLE; + notify_filter.handle.dbch_size = sizeof(notify_filter.handle); + notify_filter.handle.dbch_handle = filter->u.DeviceHandle.hTarget; + break; + case CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE: + FIXME( "CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE is not supported!\n" ); + return CR_CALL_NOT_IMPLEMENTED; + default: + return CR_INVALID_DATA; + } + + if (!(ctx = calloc( 1, sizeof(*ctx) ))) return CR_OUT_OF_MEMORY; + + ctx->user_data = user_data; + ctx->callback = callback; + if (!(ctx->notify = I_ScRegisterDeviceNotification( ctx, ¬ify_filter.header, devnotify_callback ))) + { + free( ctx ); + switch (GetLastError()) + { + case ERROR_NOT_ENOUGH_MEMORY: return CR_OUT_OF_MEMORY; + case ERROR_INVALID_PARAMETER: return CR_INVALID_DATA; + default: return CR_FAILURE; + } + } + *notify_handle = ctx; + return CR_SUCCESS; +} + +/*********************************************************************** + * CM_Register_Notification (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Register_Notification( CM_NOTIFY_FILTER *filter, void *context, + PCM_NOTIFY_CALLBACK callback, HCMNOTIFICATION *notify_context ) +{ + TRACE( "(%s %p %p %p)\n", debugstr_CM_NOTIFY_FILTER( filter ), context, callback, notify_context ); + + if (!notify_context) return CR_FAILURE; + if (!filter || !callback || filter->cbSize != sizeof(*filter)) return CR_INVALID_DATA; + + return create_notify_context( filter, notify_context, callback, context ); +} + +/*********************************************************************** + * CM_Unregister_Notification (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Unregister_Notification( HCMNOTIFICATION notify ) +{ + struct cm_notify_context *ctx = notify; + + TRACE( "(%p)\n", notify ); + + if (!notify) return CR_INVALID_DATA; + + I_ScUnregisterDeviceNotification( ctx->notify ); + free( ctx ); + + return CR_SUCCESS; +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10078
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 58 ++++++++++++++++++ dlls/cfgmgr32/cfgmgr32.spec | 8 +-- dlls/cfgmgr32/tests/cfgmgr32.c | 105 ++++++++++++++++++++++++++++++++- 3 files changed, 165 insertions(+), 6 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 7362069490a..f01b2aabd3e 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -23,6 +23,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(setupapi); +static const WCHAR *guid_string( const GUID *guid, WCHAR *buffer, UINT length ) +{ + swprintf( buffer, length, L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], + guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] ); + return buffer; +} + /*********************************************************************** * CM_MapCrToWin32Err (cfgmgr32.@) */ @@ -59,6 +67,56 @@ DWORD WINAPI CM_MapCrToWin32Err( CONFIGRET code, DWORD default_error ) return default_error; } +/*********************************************************************** + * CM_Get_Class_Key_Name_ExW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Class_Key_Name_ExW( GUID *guid, WCHAR *name, ULONG *len, ULONG flags, HMACHINE machine ) +{ + UINT capacity; + + TRACE( "guid %s, name %p, len %p, flags %#lx, machine %p\n", debugstr_guid(guid), name, len, flags, machine ); + if (machine) FIXME( "machine %p not implemented!\n", machine ); + if (flags) FIXME( "flags %#lx not implemented!\n", flags ); + + if (!guid || !len) return CR_INVALID_POINTER; + if ((capacity = *len) && !name) return CR_INVALID_POINTER; + + *len = 39; + if (capacity < *len) return CR_BUFFER_SMALL; + guid_string( guid, name, capacity ); + return CR_SUCCESS; +} + +/*********************************************************************** + * CM_Get_Class_Key_Name_ExA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Class_Key_Name_ExA( GUID *class, char *nameA, ULONG *len, ULONG flags, HMACHINE machine ) +{ + WCHAR nameW[39]; + CONFIGRET ret; + + if ((ret = CM_Get_Class_Key_Name_ExW( class, nameA ? nameW : NULL, len, flags, machine ))) return ret; + if (nameA) WideCharToMultiByte( CP_ACP, 0, nameW, 39, nameA, 39, NULL, NULL ); + + return CR_SUCCESS; +} + +/*********************************************************************** + * CM_Get_Class_Key_NameW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Class_Key_NameW( GUID *class, WCHAR *name, ULONG *len, ULONG flags ) +{ + return CM_Get_Class_Key_Name_ExW( class, name, len, flags, NULL ); +} + +/*********************************************************************** + * CM_Get_Class_Key_NameA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Class_Key_NameA( GUID *class, char *name, ULONG *len, ULONG flags ) +{ + return CM_Get_Class_Key_Name_ExA( class, name, len, flags, NULL ); +} + /*********************************************************************** * CM_Get_Device_Interface_PropertyW (cfgmgr32.@) */ diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 862045663b6..c5b6107e736 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -64,10 +64,10 @@ @ stub CM_Free_Resource_Conflict_Handle @ stdcall CM_Get_Child(ptr long long) setupapi.CM_Get_Child @ stdcall CM_Get_Child_Ex(ptr long long ptr) setupapi.CM_Get_Child_Ex -@ stub CM_Get_Class_Key_NameA -@ stub CM_Get_Class_Key_NameW -@ stub CM_Get_Class_Key_Name_ExA -@ stub CM_Get_Class_Key_Name_ExW +@ stdcall CM_Get_Class_Key_NameA(ptr ptr ptr long) +@ stdcall CM_Get_Class_Key_NameW(ptr ptr ptr long) +@ stdcall CM_Get_Class_Key_Name_ExA(ptr ptr ptr long ptr) +@ stdcall CM_Get_Class_Key_Name_ExW(ptr ptr ptr long ptr) @ stub CM_Get_Class_NameA @ stub CM_Get_Class_NameW @ stub CM_Get_Class_Name_ExA diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 7f529e04269..271c5d515ef 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -17,11 +17,17 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "wine/test.h" -#include "winreg.h" +#include <stddef.h> +#include <stdarg.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" + +#include "winreg.h" #include "winuser.h" +#include "winternl.h" #include "objbase.h" #include "devguid.h" #include "initguid.h" @@ -32,6 +38,38 @@ #include "ntddvdeo.h" #include "devfiltertypes.h" #include "devquery.h" +#include "ddk/hidclass.h" + +#include "wine/test.h" + +static const char *debugstr_ok( const char *cond ) +{ + int c, n = 0; + /* skip possible casts */ + while ((c = *cond++)) + { + if (c == '(') n++; + if (!n) break; + if (c == ')') n--; + } + if (!strchr( cond - 1, '(' )) return wine_dbg_sprintf( "got %s", cond - 1 ); + return wine_dbg_sprintf( "%.*s returned", (int)strcspn( cond - 1, "( " ), cond - 1 ); +} + +#define ok_wcs( e, r ) \ + do \ + { \ + const WCHAR *v = (r); \ + ok( !wcscmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_w(v) ); \ + } while (0) +#define ok_ex( r, op, e, t, f, ... ) \ + do \ + { \ + t v = (r); \ + ok( v op (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \ + } while (0) +#define ok_u4( r, op, e ) ok_ex( r, op, e, UINT, "%u" ) +#define ok_x4( r, op, e ) ok_ex( r, op, e, UINT, "%#x" ) static void test_CM_MapCrToWin32Err(void) { @@ -1862,6 +1900,68 @@ static void test_DevFindProperty_invalid( void ) ok( !prop, "got prop %p\n", prop ); } +static void test_CM_Get_Class_Key_Name(void) +{ + GUID guid = GUID_DEVCLASS_DISPLAY; + WCHAR buffer[MAX_PATH]; + CONFIGRET ret; + ULONG len; + + len = ARRAY_SIZE(buffer); + ret = CM_Get_Class_Key_NameW( NULL, buffer, &len, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ok_u4( len, ==, ARRAY_SIZE(buffer) ); + + ret = CM_Get_Class_Key_NameW( &guid, NULL, NULL, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ok_u4( len, ==, ARRAY_SIZE(buffer) ); + + ret = CM_Get_Class_Key_NameW( &guid, buffer, NULL, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ok_u4( len, ==, ARRAY_SIZE(buffer) ); + + ret = CM_Get_Class_Key_NameW( &guid, NULL, &len, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ok_u4( len, ==, ARRAY_SIZE(buffer) ); + + len = 0; + ret = CM_Get_Class_Key_NameW( &guid, NULL, &len, 0 ); + ok_x4( ret, ==, CR_BUFFER_SMALL ); + ok_u4( len, ==, 39 ); + len = 1; + ret = CM_Get_Class_Key_NameW( &guid, NULL, &len, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ok_u4( len, ==, 1 ); + + len = 2; + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Key_NameW( &guid, buffer, &len, 0 ); + ok_x4( ret, ==, CR_BUFFER_SMALL ); + ok_u4( len, ==, 39 ); + ok( *buffer == 0xcdcd, "got %s\n", debugstr_wn(buffer, 2) ); + + len = ARRAY_SIZE(buffer); + ret = CM_Get_Class_Key_NameW( &guid, buffer, &len, 0 ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_u4( len, ==, 39 ); + ok_wcs( L"{4d36e968-e325-11ce-bfc1-08002be10318}", buffer ); + + /* doesn't really check anything, it works with any GUID */ + guid = GUID_DEVINTERFACE_DISPLAY_ADAPTER; + len = ARRAY_SIZE(buffer); + ret = CM_Get_Class_Key_NameW( &guid, buffer, &len, 0 ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_u4( len, ==, 39 ); + ok_wcs( L"{5b45201d-f2f2-4f3b-85bb-30ff1f953599}", buffer ); + + memset( &guid, 0xcd, sizeof(guid) ); + len = ARRAY_SIZE(buffer); + ret = CM_Get_Class_Key_NameW( &guid, buffer, &len, 0 ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_u4( len, ==, 39 ); + ok_wcs( L"{cdcdcdcd-cdcd-cdcd-cdcd-cdcdcdcdcdcd}", buffer ); +} + START_TEST(cfgmgr32) { HMODULE mod = GetModuleHandleA("cfgmgr32.dll"); @@ -1874,6 +1974,7 @@ START_TEST(cfgmgr32) pDevFindProperty = (void *)GetProcAddress(mod, "DevFindProperty"); test_CM_MapCrToWin32Err(); + test_CM_Get_Class_Key_Name(); test_CM_Get_Device_ID_List(); test_CM_Register_Notification(); test_CM_Get_Device_Interface_List(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10078
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/setupapi/setupapi.spec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index 9ac1c6c9831..436514474c5 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -55,10 +55,10 @@ @ stub CM_Free_Res_Des_Handle @ stdcall CM_Get_Child(ptr long long) @ stdcall CM_Get_Child_Ex(ptr long long ptr) -@ stub CM_Get_Class_Key_NameA -@ stub CM_Get_Class_Key_NameW -@ stub CM_Get_Class_Key_Name_ExA -@ stub CM_Get_Class_Key_Name_ExW +@ stdcall CM_Get_Class_Key_NameA(ptr ptr ptr long) cfgmgr32.CM_Get_Class_Key_NameA +@ stdcall CM_Get_Class_Key_NameW(ptr ptr ptr long) cfgmgr32.CM_Get_Class_Key_NameW +@ stdcall CM_Get_Class_Key_Name_ExA(ptr ptr ptr long ptr) cfgmgr32.CM_Get_Class_Key_Name_ExA +@ stdcall CM_Get_Class_Key_Name_ExW(ptr ptr ptr long ptr) cfgmgr32.CM_Get_Class_Key_Name_ExW @ stub CM_Get_Class_NameA @ stub CM_Get_Class_NameW @ stub CM_Get_Class_Name_ExA -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10078
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 84 ++++++++++++++++++++++++++++++++++ dlls/cfgmgr32/cfgmgr32.spec | 8 ++-- dlls/cfgmgr32/tests/cfgmgr32.c | 73 +++++++++++++++++++++++++++++ include/cfgmgr32.h | 4 ++ 4 files changed, 165 insertions(+), 4 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index f01b2aabd3e..9b144af0052 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -31,6 +31,39 @@ static const WCHAR *guid_string( const GUID *guid, WCHAR *buffer, UINT length ) return buffer; } +static const WCHAR control_classW[] = L"System\\CurrentControlSet\\Control\\Class\\"; +static const WCHAR device_classesW[] = L"System\\CurrentControlSet\\Control\\DeviceClasses\\"; + +static LSTATUS open_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, HKEY *hkey ) +{ + if (open) return RegOpenKeyExW( root, key, 0, access, hkey ); + return RegCreateKeyExW( root, key, 0, NULL, 0, access, NULL, hkey, NULL ); +} + +static LSTATUS open_class_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, HKEY *hkey ) +{ + WCHAR path[MAX_PATH]; + swprintf( path, ARRAY_SIZE(path), L"%s%s", control_classW, key ); + return open_key( root, path, access, open, hkey ); +} + +static LSTATUS open_device_classes_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, HKEY *hkey ) +{ + WCHAR path[MAX_PATH]; + swprintf( path, ARRAY_SIZE(path), L"%s%s", device_classesW, key ); + return open_key( root, path, access, open, hkey ); +} + +static CONFIGRET map_error( LSTATUS err ) +{ + switch (err) + { + case ERROR_FILE_NOT_FOUND: return CR_NO_SUCH_REGISTRY_KEY; + case ERROR_SUCCESS: return CR_SUCCESS; + default: WARN( "unmapped error %lu\n", err ); return CR_FAILURE; + } +} + /*********************************************************************** * CM_MapCrToWin32Err (cfgmgr32.@) */ @@ -117,6 +150,57 @@ CONFIGRET WINAPI CM_Get_Class_Key_NameA( GUID *class, char *name, ULONG *len, UL return CM_Get_Class_Key_Name_ExA( class, name, len, flags, NULL ); } +/*********************************************************************** + * CM_Open_Class_Key_ExW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Class_Key_ExW( GUID *class, const WCHAR *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine ) +{ + BOOL open = disposition == RegDisposition_OpenExisting; + WCHAR buffer[39]; + + TRACE( "class %s, name %s, access %#lx, disposition %#lx, hkey %p, flags %#lx\n", debugstr_guid(class), debugstr_w(name), access, disposition, hkey, flags ); + if (machine) FIXME( "machine %p not implemented!\n", machine ); + + if (name) return CR_INVALID_DATA; + if (!hkey) return CR_INVALID_POINTER; + if (flags & ~CM_OPEN_CLASS_KEY_BITS) return CR_INVALID_FLAG; + + if (!class) *buffer = 0; + else guid_string( class, buffer, ARRAY_SIZE(buffer) ); + + if (flags == CM_OPEN_CLASS_KEY_INSTALLER) return map_error( open_class_key( HKEY_LOCAL_MACHINE, buffer, access, open, hkey ) ); + return map_error( open_device_classes_key( HKEY_LOCAL_MACHINE, buffer, access, open, hkey ) ); +} + +/*********************************************************************** + * CM_Open_Class_Key_ExA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Class_Key_ExA( GUID *class, const char *nameA, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine ) +{ + WCHAR nameW[MAX_PATH]; + + TRACE( "guid %s, nameA %s, access %#lx, disposition %#lx, hkey %p, flags %#lx\n", debugstr_guid(class), debugstr_a(nameA), access, disposition, hkey, flags ); + + if (nameA) MultiByteToWideChar( CP_ACP, 0, nameA, -1, nameW, ARRAY_SIZE(nameW) ); + return CM_Open_Class_Key_ExW( class, nameA ? nameW : NULL, access, disposition, hkey, flags, machine ); +} + +/*********************************************************************** + * CM_Open_Class_KeyW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Class_KeyW( GUID *class, const WCHAR *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags ) +{ + return CM_Open_Class_Key_ExW( class, name, access, disposition, hkey, flags, NULL ); +} + +/*********************************************************************** + * CM_Open_Class_KeyA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Class_KeyA( GUID *class, const char *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags ) +{ + return CM_Open_Class_Key_ExA( class, name, access, disposition, hkey, flags, NULL ); +} + /*********************************************************************** * CM_Get_Device_Interface_PropertyW (cfgmgr32.@) */ diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index c5b6107e736..4bafdae1ed1 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -176,10 +176,10 @@ @ stub CM_Move_DevNode @ stub CM_Move_DevNode_Ex @ stub CM_Next_Range -@ stub CM_Open_Class_KeyA -@ stub CM_Open_Class_KeyW -@ stub CM_Open_Class_Key_ExA -@ stub CM_Open_Class_Key_ExW +@ stdcall CM_Open_Class_KeyA(ptr str long long ptr long) +@ stdcall CM_Open_Class_KeyW(ptr wstr long long ptr long) +@ stdcall CM_Open_Class_Key_ExA(ptr str long long ptr long ptr) +@ stdcall CM_Open_Class_Key_ExW(ptr wstr long long ptr long ptr) @ stdcall CM_Open_DevNode_Key(long long long long ptr long) setupapi.CM_Open_DevNode_Key @ stub CM_Open_DevNode_Key_Ex @ stub CM_Open_Device_Interface_KeyA diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 271c5d515ef..0f47bdd1fa8 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -1962,6 +1962,78 @@ static void test_CM_Get_Class_Key_Name(void) ok_wcs( L"{cdcdcdcd-cdcd-cdcd-cdcd-cdcdcdcdcdcd}", buffer ); } +static BOOL compare_unicode_string( const UNICODE_STRING *string, const WCHAR *expect ) +{ + return string->Length == wcslen( expect ) * sizeof(WCHAR) && + !wcsnicmp( string->Buffer, expect, string->Length / sizeof(WCHAR) ); +} + +#define check_object_name( a, b ) _check_object_name( __LINE__, a, b ) +static void _check_object_name( unsigned line, HANDLE handle, const WCHAR *expected_name ) +{ + char buffer[1024]; + UNICODE_STRING *str = (UNICODE_STRING *)buffer, expect; + ULONG len = 0; + NTSTATUS status; + + RtlInitUnicodeString( &expect, expected_name ); + + memset( buffer, 0, sizeof(buffer) ); + status = NtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len ); + ok_(__FILE__, line)( status == STATUS_SUCCESS, "NtQueryObject failed %lx\n", status ); + ok_(__FILE__, line)( len >= sizeof(OBJECT_NAME_INFORMATION) + str->Length, "unexpected len %lu\n", len ); + ok_(__FILE__, line)( compare_unicode_string( str, expected_name ), "got %s, expected %s\n", + debugstr_w(str->Buffer), debugstr_w(expected_name) ); +} + +static void test_CM_Open_Class_Key(void) +{ + CONFIGRET ret; + GUID guid; + HKEY hkey; + + ret = CM_Open_Class_KeyW( NULL, NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, CM_OPEN_CLASS_KEY_INSTALLER ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\Class" ); + RegCloseKey( hkey ); + + ret = CM_Open_Class_KeyW( NULL, NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, CM_OPEN_CLASS_KEY_INTERFACE ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\DeviceClasses" ); + RegCloseKey( hkey ); + + guid = GUID_DEVCLASS_DISPLAY; + ret = CM_Open_Class_KeyW( &guid, NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, CM_OPEN_CLASS_KEY_INSTALLER ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}" ); + RegCloseKey( hkey ); + + guid = GUID_DEVINTERFACE_DISPLAY_ADAPTER; + ret = CM_Open_Class_KeyW( &guid, NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, CM_OPEN_CLASS_KEY_INTERFACE ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\DeviceClasses\\{5b45201d-f2f2-4f3b-85bb-30ff1f953599}" ); + RegCloseKey( hkey ); + + memset( &guid, 0xcd, sizeof(guid) ); + ret = CM_Open_Class_KeyW( &guid, NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, CM_OPEN_CLASS_KEY_INSTALLER ); + ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY ); + ret = CM_Open_Class_KeyW( &guid, NULL, KEY_QUERY_VALUE, RegDisposition_OpenAlways, &hkey, CM_OPEN_CLASS_KEY_INSTALLER ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\Class\\{cdcdcdcd-cdcd-cdcd-cdcd-cdcdcdcdcdcd}" ); + RegCloseKey( hkey ); + ret = RegDeleteKeyW( HKEY_LOCAL_MACHINE, L"SYSTEM\\ControlSet001\\Control\\Class\\{cdcdcdcd-cdcd-cdcd-cdcd-cdcdcdcdcdcd}" ); + ok_x4( ret, ==, ERROR_SUCCESS ); + + ret = CM_Open_Class_KeyW( &guid, NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, CM_OPEN_CLASS_KEY_INTERFACE ); + ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY ); + ret = CM_Open_Class_KeyW( &guid, NULL, KEY_QUERY_VALUE, RegDisposition_OpenAlways, &hkey, CM_OPEN_CLASS_KEY_INTERFACE ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\DeviceClasses\\{cdcdcdcd-cdcd-cdcd-cdcd-cdcdcdcdcdcd}" ); + RegCloseKey( hkey ); + ret = RegDeleteKeyW( HKEY_LOCAL_MACHINE, L"SYSTEM\\ControlSet001\\Control\\DeviceClasses\\{cdcdcdcd-cdcd-cdcd-cdcd-cdcdcdcdcdcd}" ); + ok_x4( ret, ==, ERROR_SUCCESS ); +} + START_TEST(cfgmgr32) { HMODULE mod = GetModuleHandleA("cfgmgr32.dll"); @@ -1975,6 +2047,7 @@ START_TEST(cfgmgr32) test_CM_MapCrToWin32Err(); test_CM_Get_Class_Key_Name(); + test_CM_Open_Class_Key(); test_CM_Get_Device_ID_List(); test_CM_Register_Notification(); test_CM_Get_Device_Interface_List(); diff --git a/include/cfgmgr32.h b/include/cfgmgr32.h index e1f417a93a7..29a3673dbe9 100644 --- a/include/cfgmgr32.h +++ b/include/cfgmgr32.h @@ -201,6 +201,10 @@ typedef DWORD CONFIGRET; #define CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES 0x00000001 #define CM_GET_DEVICE_INTERFACE_LIST_BITS 0x00000001 +#define CM_OPEN_CLASS_KEY_INSTALLER 0x00000000 +#define CM_OPEN_CLASS_KEY_INTERFACE 0x00000001 +#define CM_OPEN_CLASS_KEY_BITS 0x00000001 + typedef DWORD DEVINST, *PDEVINST; typedef DWORD DEVNODE, *PDEVNODE; typedef HANDLE HMACHINE, *PHMACHINE; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10078
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/setupapi/setupapi.spec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index 436514474c5..0a713d96984 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -142,10 +142,10 @@ @ stub CM_Move_DevNode @ stub CM_Move_DevNode_Ex @ stub CM_Next_Range -@ stub CM_Open_Class_KeyA -@ stub CM_Open_Class_KeyW -@ stub CM_Open_Class_Key_ExA -@ stub CM_Open_Class_Key_ExW +@ stdcall CM_Open_Class_KeyA(ptr str long long ptr long) cfgmgr32.CM_Open_Class_KeyA +@ stdcall CM_Open_Class_KeyW(ptr wstr long long ptr long) cfgmgr32.CM_Open_Class_KeyW +@ stdcall CM_Open_Class_Key_ExA(ptr str long long ptr long ptr) cfgmgr32.CM_Open_Class_Key_ExA +@ stdcall CM_Open_Class_Key_ExW(ptr wstr long long ptr long ptr) cfgmgr32.CM_Open_Class_Key_ExW @ stdcall CM_Open_DevNode_Key(long long long long ptr long) @ stub CM_Open_DevNode_Key_Ex @ stub CM_Query_And_Remove_SubTreeA -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10078
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 9b144af0052..2a2e9f96d33 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -34,8 +34,40 @@ static const WCHAR *guid_string( const GUID *guid, WCHAR *buffer, UINT length ) static const WCHAR control_classW[] = L"System\\CurrentControlSet\\Control\\Class\\"; static const WCHAR device_classesW[] = L"System\\CurrentControlSet\\Control\\DeviceClasses\\"; +static struct key_cache +{ + HKEY root; + const WCHAR *prefix; + UINT prefix_len; + HKEY hkey; +} cache[] = +{ + { HKEY_LOCAL_MACHINE, control_classW, ARRAY_SIZE(control_classW) - 1, (HKEY)-1 }, + { HKEY_LOCAL_MACHINE, device_classesW, ARRAY_SIZE(device_classesW) - 1, (HKEY)-1 }, +}; + +static HKEY cache_root_key( HKEY root, const WCHAR *key, const WCHAR **path ) +{ + HKEY hkey; + + for (struct key_cache *entry = cache; entry < cache + ARRAY_SIZE(cache); entry++) + { + if (entry->root != root) continue; + if (wcsnicmp( key, entry->prefix, entry->prefix_len )) continue; + if (path) *path = key + entry->prefix_len; + + if (entry->hkey != (HKEY)-1 || RegOpenKeyExW( root, entry->prefix, 0, KEY_ALL_ACCESS, &hkey )) return entry->hkey; + if (InterlockedCompareExchangePointer( (void *)&entry->hkey, hkey, (HKEY)-1 ) != (HKEY)-1) RegCloseKey( hkey ); + return entry->hkey; + } + + if (path) *path = key; + return root; +} + static LSTATUS open_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, HKEY *hkey ) { + if ((root = cache_root_key( root, key, &key )) == (HKEY)-1) return ERROR_FILE_NOT_FOUND; if (open) return RegOpenKeyExW( root, key, 0, access, hkey ); return RegCreateKeyExW( root, key, 0, NULL, 0, access, NULL, hkey, NULL ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10078
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 40 ++++++++++++++++++++++++++++++++++ dlls/cfgmgr32/cfgmgr32.spec | 4 ++-- dlls/cfgmgr32/tests/cfgmgr32.c | 33 ++++++++++++++++++++++++++++ include/cfgmgr32.h | 4 ++++ 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 2a2e9f96d33..2d85662b47a 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -23,6 +23,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(setupapi); +static LSTATUS guid_from_string( const WCHAR *str, GUID *guid ) +{ + UNICODE_STRING guid_str; + RtlInitUnicodeString( &guid_str, str ); + if (RtlGUIDFromString( &guid_str, guid )) return ERROR_INVALID_DATA; + return ERROR_SUCCESS; +} + static const WCHAR *guid_string( const GUID *guid, WCHAR *buffer, UINT length ) { swprintf( buffer, length, L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", @@ -91,6 +99,7 @@ static CONFIGRET map_error( LSTATUS err ) switch (err) { case ERROR_FILE_NOT_FOUND: return CR_NO_SUCH_REGISTRY_KEY; + case ERROR_NO_MORE_ITEMS: return CR_NO_SUCH_VALUE; case ERROR_SUCCESS: return CR_SUCCESS; default: WARN( "unmapped error %lu\n", err ); return CR_FAILURE; } @@ -132,6 +141,37 @@ DWORD WINAPI CM_MapCrToWin32Err( CONFIGRET code, DWORD default_error ) return default_error; } +/*********************************************************************** + * CM_Enumerate_Classes_Ex (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Enumerate_Classes_Ex( ULONG index, GUID *class, ULONG flags, HMACHINE machine ) +{ + WCHAR buffer[39]; + LSTATUS err; + HKEY root; + + TRACE( "index %lu, class %s, flags %#lx, machine %p\n", index, debugstr_guid(class), flags, machine ); + if (machine) FIXME( "machine %p not implemented!\n", machine ); + + if (!class) return CR_INVALID_POINTER; + if (flags & ~CM_ENUMERATE_CLASSES_BITS) return CR_INVALID_FLAG; + + if (flags == CM_ENUMERATE_CLASSES_INSTALLER) root = cache_root_key( HKEY_LOCAL_MACHINE, control_classW, NULL ); + else root = cache_root_key( HKEY_LOCAL_MACHINE, device_classesW, NULL ); + if (root == (HKEY)-1) return CR_NO_SUCH_REGISTRY_KEY; + + if ((err = RegEnumKeyW( root, index, buffer, ARRAY_SIZE(buffer) ))) return map_error( err ); + return map_error( guid_from_string( buffer, class ) ); +} + +/*********************************************************************** + * CM_Enumerate_Classes (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Enumerate_Classes( ULONG index, GUID *class, ULONG flags ) +{ + return CM_Enumerate_Classes_Ex( index, class, flags, NULL ); +} + /*********************************************************************** * CM_Get_Class_Key_Name_ExW (cfgmgr32.@) */ diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 4bafdae1ed1..4865cadaf53 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -46,8 +46,8 @@ @ stub CM_Duplicate_PowerScheme @ stub CM_Enable_DevNode @ stub CM_Enable_DevNode_Ex -@ stdcall CM_Enumerate_Classes(long ptr long) setupapi.CM_Enumerate_Classes -@ stub CM_Enumerate_Classes_Ex +@ stdcall CM_Enumerate_Classes(long ptr long) +@ stdcall CM_Enumerate_Classes_Ex(long ptr long ptr) @ stub CM_Enumerate_EnumeratorsA @ stub CM_Enumerate_EnumeratorsW @ stub CM_Enumerate_Enumerators_ExA diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 0f47bdd1fa8..c2d9d4d7c34 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -1900,6 +1900,38 @@ static void test_DevFindProperty_invalid( void ) ok( !prop, "got prop %p\n", prop ); } +static void test_CM_Enumerate_Classes(void) +{ + CONFIGRET ret; + GUID guid; + + ret = CM_Enumerate_Classes( 0, NULL, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + for (UINT flag = 2; flag; flag <<= 1) + { + winetest_push_context( "%#x", flag ); + ret = CM_Enumerate_Classes( 0, &guid, flag ); + ok_x4( ret, ==, CR_INVALID_FLAG ); + winetest_pop_context(); + } + ret = CM_Enumerate_Classes( -1, &guid, 0 ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + + for (UINT i = 0; !(ret = CM_Enumerate_Classes( i, &guid, CM_ENUMERATE_CLASSES_INSTALLER )); i++) + if (IsEqualGUID( &guid, &GUID_DEVINTERFACE_HID )) break; + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + for (UINT i = 0; !(ret = CM_Enumerate_Classes( i, &guid, CM_ENUMERATE_CLASSES_INSTALLER )); i++) + if (IsEqualGUID( &guid, &GUID_DEVCLASS_HIDCLASS )) break; + ok_x4( ret, ==, CR_SUCCESS ); + + for (UINT i = 0; !(ret = CM_Enumerate_Classes( i, &guid, CM_ENUMERATE_CLASSES_INTERFACE )); i++) + if (IsEqualGUID( &guid, &GUID_DEVINTERFACE_HID )) break; + ok_x4( ret, ==, CR_SUCCESS ); + for (UINT i = 0; !(ret = CM_Enumerate_Classes( i, &guid, CM_ENUMERATE_CLASSES_INTERFACE )); i++) + if (IsEqualGUID( &guid, &GUID_DEVCLASS_HIDCLASS )) break; + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); +} + static void test_CM_Get_Class_Key_Name(void) { GUID guid = GUID_DEVCLASS_DISPLAY; @@ -2046,6 +2078,7 @@ START_TEST(cfgmgr32) pDevFindProperty = (void *)GetProcAddress(mod, "DevFindProperty"); test_CM_MapCrToWin32Err(); + test_CM_Enumerate_Classes(); test_CM_Get_Class_Key_Name(); test_CM_Open_Class_Key(); test_CM_Get_Device_ID_List(); diff --git a/include/cfgmgr32.h b/include/cfgmgr32.h index 29a3673dbe9..43a2157f1cf 100644 --- a/include/cfgmgr32.h +++ b/include/cfgmgr32.h @@ -205,6 +205,10 @@ typedef DWORD CONFIGRET; #define CM_OPEN_CLASS_KEY_INTERFACE 0x00000001 #define CM_OPEN_CLASS_KEY_BITS 0x00000001 +#define CM_ENUMERATE_CLASSES_INSTALLER 0x00000000 +#define CM_ENUMERATE_CLASSES_INTERFACE 0x00000001 +#define CM_ENUMERATE_CLASSES_BITS 0x00000001 + typedef DWORD DEVINST, *PDEVINST; typedef DWORD DEVNODE, *PDEVNODE; typedef HANDLE HMACHINE, *PHMACHINE; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10078
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/setupapi/setupapi.spec | 4 ++-- dlls/setupapi/stubs.c | 9 --------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index 0a713d96984..7fea0020bc9 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -38,8 +38,8 @@ @ stub CM_Dup_Range_List @ stub CM_Enable_DevNode @ stub CM_Enable_DevNode_Ex -@ stdcall CM_Enumerate_Classes(long ptr long) -@ stub CM_Enumerate_Classes_Ex +@ stdcall CM_Enumerate_Classes(long ptr long) cfgmgr32.CM_Enumerate_Classes +@ stdcall CM_Enumerate_Classes_Ex(long ptr long ptr) cfgmgr32.CM_Enumerate_Classes_Ex @ stub CM_Enumerate_EnumeratorsA @ stub CM_Enumerate_EnumeratorsW @ stub CM_Enumerate_Enumerators_ExA diff --git a/dlls/setupapi/stubs.c b/dlls/setupapi/stubs.c index 96b12cb8a44..12cf85ad5a6 100644 --- a/dlls/setupapi/stubs.c +++ b/dlls/setupapi/stubs.c @@ -344,15 +344,6 @@ CONFIGRET WINAPI CM_Get_DevNode_Status_Ex(ULONG *status, ULONG *problem, DEVINST return CR_SUCCESS; } -/*********************************************************************** - * CM_Enumerate_Classes (SETUPAPI.@) - */ -CONFIGRET WINAPI CM_Enumerate_Classes(ULONG index, LPGUID class, ULONG flags) -{ - FIXME("%lu %p 0x%08lx: stub\n", index, class, flags); - return CR_NO_SUCH_VALUE; -} - /*********************************************************************** * CM_Get_Class_Registry_PropertyA (SETUPAPI.@) */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10078
v3: Forward functions from setupapi to cfgmgr32 instead of sharing sources, as it seems to work after all. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10078#note_129615
participants (2)
-
Rémi Bernon -
Rémi Bernon (@rbernon)