From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 87 ++++++++++++++++++++++++++++++++++ dlls/cfgmgr32/cfgmgr32.spec | 8 ++-- dlls/cfgmgr32/tests/cfgmgr32.c | 49 +++++++++++++++++++ 3 files changed, 140 insertions(+), 4 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 60320f94a96..c47e50f37e5 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -96,6 +96,37 @@ static LSTATUS open_device_classes_key( HKEY root, const WCHAR *key, REGSAM acce return open_key( root, path, access, open, hkey ); } +struct device_interface +{ + GUID class_guid; + WCHAR class[39]; + WCHAR name[MAX_PATH]; + WCHAR refstr[MAX_PATH]; +}; + +static LSTATUS init_device_interface( struct device_interface *iface, const WCHAR *name ) +{ + WCHAR *tmp; + UINT len; + + if (wcsncmp( name, L"\\\\?\\", 4 )) return ERROR_FILE_NOT_FOUND; + len = swprintf( iface->name, MAX_PATH, L"##?#%s", name + 4 ); + + if ((tmp = wcschr( iface->name, '\\' ))) *tmp++ = 0; + else tmp = iface->name + len; + swprintf( iface->refstr, MAX_PATH, L"#%s", tmp ); + + if (!(tmp = wcsrchr( iface->name, '#' ))) return ERROR_FILE_NOT_FOUND; + return guid_from_string( wcscpy( iface->class, tmp + 1 ), &iface->class_guid ); +} + +static LSTATUS open_device_interface_key( const struct device_interface *iface, REGSAM access, BOOL open, HKEY *hkey ) +{ + WCHAR path[MAX_PATH]; + swprintf( path, ARRAY_SIZE(path), L"%s\\%s", iface->class, iface->name ); + return open_device_classes_key( HKEY_LOCAL_MACHINE, path, access, open, hkey ); +} + static CONFIGRET map_error( LSTATUS err ) { switch (err) @@ -334,6 +365,62 @@ CONFIGRET WINAPI CM_Open_Class_KeyA( GUID *class, const char *name, REGSAM acces return CM_Open_Class_Key_ExA( class, name, access, disposition, hkey, flags, NULL ); } +/*********************************************************************** + * CM_Open_Device_Interface_Key_ExW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Device_Interface_Key_ExW( const WCHAR *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine ) +{ + BOOL open = disposition == RegDisposition_OpenExisting; + struct device_interface iface; + WCHAR path[MAX_PATH]; + HKEY iface_key; + LSTATUS err; + + TRACE( "name %s, access %#lx, disposition %#lx, hkey %p, flags %#lx\n", debugstr_w(name), access, disposition, hkey, flags ); + if (machine) FIXME( "machine %p not implemented!\n", machine ); + + if (!name) return CR_INVALID_POINTER; + if (init_device_interface( &iface, name )) return CR_INVALID_DATA; + if (!hkey) return CR_INVALID_POINTER; + if (flags) return CR_INVALID_FLAG; + + if (open_device_interface_key( &iface, KEY_ALL_ACCESS, TRUE, &iface_key )) return CR_NO_SUCH_DEVICE_INTERFACE; + swprintf( path, ARRAY_SIZE(path), L"%s\\Device Parameters", iface.refstr ); + err = open_key( iface_key, path, access, open, hkey ); + RegCloseKey( iface_key ); + + return map_error( err ); +} + +/*********************************************************************** + * CM_Open_Device_Interface_Key_ExA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Device_Interface_Key_ExA( const char *ifaceA, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine ) +{ + WCHAR ifaceW[MAX_PATH]; + + TRACE( "ifaceA %s, access %#lx, disposition %#lx, hkey %p, flags %#lx\n", debugstr_a(ifaceA), access, disposition, hkey, flags ); + + if (ifaceA) MultiByteToWideChar( CP_ACP, 0, ifaceA, -1, ifaceW, ARRAY_SIZE(ifaceW) ); + return CM_Open_Device_Interface_Key_ExW( ifaceA ? ifaceW : NULL, access, disposition, hkey, flags, machine ); +} + +/*********************************************************************** + * CM_Open_Device_Interface_KeyW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Device_Interface_KeyW( const WCHAR *iface, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags ) +{ + return CM_Open_Device_Interface_Key_ExW( iface, access, disposition, hkey, flags, NULL ); +} + +/*********************************************************************** + * CM_Open_Device_Interface_KeyA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Device_Interface_KeyA( const char *iface, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags ) +{ + return CM_Open_Device_Interface_Key_ExA( iface, access, disposition, hkey, flags, NULL ); +} + /*********************************************************************** * CM_Get_Device_Interface_PropertyW (cfgmgr32.@) */ diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 457654f2324..0695e73a685 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -182,10 +182,10 @@ @ 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 -@ stub CM_Open_Device_Interface_KeyW -@ stub CM_Open_Device_Interface_Key_ExA -@ stub CM_Open_Device_Interface_Key_ExW +@ stdcall CM_Open_Device_Interface_KeyA(str long long ptr long) +@ stdcall CM_Open_Device_Interface_KeyW(wstr long long ptr long) +@ stdcall CM_Open_Device_Interface_Key_ExA(str long long ptr long ptr) +@ stdcall CM_Open_Device_Interface_Key_ExW(wstr long long ptr long ptr) @ stub CM_Query_And_Remove_SubTreeA @ stub CM_Query_And_Remove_SubTreeW @ stub CM_Query_And_Remove_SubTree_ExA diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index f26abb72913..4bc26755ad3 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -71,6 +71,14 @@ static const char *debugstr_ok( const char *cond ) #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 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; +} + static void test_CM_MapCrToWin32Err(void) { unsigned int i; @@ -2113,6 +2121,46 @@ static void test_CM_Open_Class_Key(void) ok_x4( ret, ==, ERROR_SUCCESS ); } +static void test_CM_Open_Device_Interface_Key(void) +{ + WCHAR iface[4096], name[MAX_PATH], expect[MAX_PATH], buffer[39], *refstr; + CONFIGRET ret; + HKEY hkey; + GUID guid; + + guid = GUID_DEVINTERFACE_HID; + ret = CM_Get_Device_Interface_ListW( &guid, NULL, iface, ARRAY_SIZE(iface), CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_SUCCESS ); + + wcscpy( name, iface + 4 ); + if ((refstr = wcschr( name, '\\' ))) *refstr++ = 0; + else refstr = (WCHAR *)L""; + swprintf( expect, ARRAY_SIZE(expect), L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\DeviceClasses\\%s\\##?#%s\\#%s\\Device Parameters", + guid_string( &guid, buffer, ARRAY_SIZE(buffer) ), name, refstr ); + + ret = CM_Open_Device_Interface_KeyW( NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ret = CM_Open_Device_Interface_KeyW( L"DISPLAY_ADAPTER", KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, 0 ); + ok_x4( ret, ==, CR_INVALID_DATA ); + ret = CM_Open_Device_Interface_KeyW( L"\\\\?\\WINETEST#WINETEST#0123456#{5b45201d-f2f2-4f3b-85bb-30ff1f953599}", KEY_QUERY_VALUE, RegDisposition_OpenAlways, &hkey, 0 ); + ok_x4( ret, ==, CR_NO_SUCH_DEVICE_INTERFACE ); + + ret = CM_Open_Device_Interface_KeyW( iface, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, 0 ); + if (ret == CR_NO_SUCH_REGISTRY_KEY) ret = CM_Open_Device_Interface_KeyW( iface, KEY_QUERY_VALUE, RegDisposition_OpenAlways, &hkey, 0 ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, expect ); + RegCloseKey( hkey ); + if (ret == CR_NO_SUCH_REGISTRY_KEY) RegDeleteKeyW( HKEY_LOCAL_MACHINE, expect + wcslen( L"\\REGISTRY\\MACHINE\\" ) ); + + for (UINT flag = 1; flag; flag <<= 1) + { + winetest_push_context( "%#x", flag ); + ret = CM_Open_Device_Interface_KeyW( iface, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, flag ); + ok_x4( ret, ==, CR_INVALID_FLAG ); + winetest_pop_context(); + } +} + START_TEST(cfgmgr32) { HMODULE mod = GetModuleHandleA("cfgmgr32.dll"); @@ -2129,6 +2177,7 @@ START_TEST(cfgmgr32) test_CM_Enumerate_Enumerators(); test_CM_Get_Class_Key_Name(); test_CM_Open_Class_Key(); + test_CM_Open_Device_Interface_Key(); 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/10110