From: Vibhav Pant vibhavp@gmail.com
--- dlls/setupapi/devinst.c | 93 +++++++++++++++++++++++++++++++++-- dlls/setupapi/tests/devinst.c | 26 +++++----- 2 files changed, 103 insertions(+), 16 deletions(-)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index fdd9edcd6ec..ccbc4a321f3 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -46,6 +46,8 @@
#include "setupapi_private.h"
+#include "initguid.h" +#include "devpkey.h"
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
@@ -3120,10 +3122,95 @@ BOOL WINAPI SetupDiSetDeviceInterfacePropertyW( HDEVINFO devinfo, SP_DEVICE_INTE const DEVPROPKEY *key, DEVPROPTYPE type, const BYTE *buf, DWORD buf_size, DWORD flags ) { - FIXME( "devinfo %p, iface_data %p, key %p, type %#lx, buf %p, buf_size %lu, flags %#lx: stub!\n", devinfo, + WCHAR prop_path[44]; + struct device_iface *iface; + HKEY properties, property; + LSTATUS ret; + + TRACE( "devinfo %p, iface_data %p, key %p, type %#lx, buf %p, buf_size %lu, flags %#lx\n", devinfo, iface_data, key, type, buf, buf_size, flags ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + + if (!devinfo) + { + SetLastError( ERROR_INVALID_HANDLE ); + return FALSE; + } + if (!iface_data) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + if (buf_size && !buf) + { + SetLastError( ERROR_INVALID_USER_BUFFER ); + return FALSE; + } + if (!key || !is_valid_property_type(type) + || (!(buf && buf_size) && !(type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL)) + || (buf && buf_size && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL))) + { + SetLastError( ERROR_INVALID_DATA ); + return FALSE; + } + if (flags) + { + SetLastError( ERROR_INVALID_FLAGS ); + return FALSE; + } + if (!(iface = get_device_iface(devinfo, iface_data))) + return FALSE; + + if (IsEqualDevPropKey( *key, DEVPKEY_DeviceInterface_Enabled )) + { + DEVPROP_BOOLEAN val = *(DEVPROP_BOOLEAN *)buf; + + if (type != DEVPROP_TYPE_BOOLEAN || buf_size != sizeof( DEVPROP_BOOLEAN ) + || !(val == DEVPROP_FALSE || val == DEVPROP_TRUE)) + { + SetLastError( ERROR_INVALID_DATA ); + return FALSE; + } + + ret = is_linked( iface->class_key ) == !!val ? ERROR_SUCCESS : ERROR_ACCESS_DENIED; + /* Setting this to the interface's current status is a no-op, otherwise return ERROR_ACCESS_DENEID. */ + SetLastError( ret ); + return !ret; + } + + ret = RegCreateKeyExW( iface->refstr_key, L"Properties", 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &properties, NULL ); + if (ret) + { + SetLastError( ret ); + return FALSE; + } + + SETUPDI_GuidToString( &key->fmtid, prop_path ); + swprintf( &prop_path[38], ARRAY_SIZE( prop_path ) - 38, L"\%04X", key->pid ); + switch (type) + { + case DEVPROP_TYPE_EMPTY: + ret = RegDeleteKeyW( properties, prop_path ); + SetLastError( ret == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ret ); + break; + case DEVPROP_TYPE_NULL: + if (!(ret = RegOpenKeyW( properties, prop_path, &property ))) + { + ret = RegDeleteValueW( property, NULL ); + RegCloseKey( property ); + } + break; + default: + if (!(ret = RegCreateKeyExW( properties, prop_path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &property, NULL ))) + { + ret = RegSetValueExW( property, NULL, 0, 0xffff0000 | ( 0xffff & type ), buf, buf_size ); + RegCloseKey( property ); + } + break; + } + + RegCloseKey( properties ); + SetLastError( ret == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ret ); + return !ret; }
/*********************************************************************** diff --git a/dlls/setupapi/tests/devinst.c b/dlls/setupapi/tests/devinst.c index 6357b694366..d1a7418e29b 100644 --- a/dlls/setupapi/tests/devinst.c +++ b/dlls/setupapi/tests/devinst.c @@ -2750,35 +2750,35 @@ static void test_device_interface_properties(void)
ret = SetupDiSetDeviceInterfacePropertyW(NULL, NULL, NULL, DEVPROP_TYPE_STRING, NULL, 0, 0); err = GetLastError(); - todo_wine ok(!ret && err == ERROR_INVALID_HANDLE, "%lu != %d\n", err, ERROR_INVALID_HANDLE); + ok(!ret && err == ERROR_INVALID_HANDLE, "%lu != %d\n", err, ERROR_INVALID_HANDLE);
ret = SetupDiSetDeviceInterfacePropertyW(set, NULL, NULL, DEVPROP_TYPE_STRING, NULL, 0, 0); err = GetLastError(); - todo_wine ok(!ret && err == ERROR_INVALID_PARAMETER, "%lu != %d\n", err, ERROR_INVALID_PARAMETER); + ok(!ret && err == ERROR_INVALID_PARAMETER, "%lu != %d\n", err, ERROR_INVALID_PARAMETER);
ret = SetupDiSetDeviceInterfacePropertyW(set, &iface, NULL, DEVPROP_TYPE_STRING, NULL, 0, 0); err = GetLastError(); - todo_wine ok(!ret && err == ERROR_INVALID_DATA, "%lu != %d\n", err, ERROR_INVALID_DATA); + ok(!ret && err == ERROR_INVALID_DATA, "%lu != %d\n", err, ERROR_INVALID_DATA);
ret = SetupDiSetDeviceInterfacePropertyW(set, &iface, &DEVPKEY_DeviceInterface_FriendlyName, DEVPROP_TYPE_STRING, NULL, 0, 0); err = GetLastError(); - todo_wine ok(!ret && err == ERROR_INVALID_DATA, "%lu != %d\n", err, ERROR_INVALID_DATA); + ok(!ret && err == ERROR_INVALID_DATA, "%lu != %d\n", err, ERROR_INVALID_DATA);
ret = SetupDiSetDeviceInterfacePropertyW(set, &iface, &DEVPKEY_DeviceInterface_FriendlyName, DEVPROP_TYPE_STRING, (BYTE *)str, 0, 0); err = GetLastError(); - todo_wine ok(!ret && err == ERROR_INVALID_DATA, "%lu != %d\n", err, ERROR_INVALID_DATA); + ok(!ret && err == ERROR_INVALID_DATA, "%lu != %d\n", err, ERROR_INVALID_DATA);
ret = SetupDiSetDeviceInterfacePropertyW(set, &iface, &DEVPKEY_DeviceInterface_FriendlyName, DEVPROP_TYPE_STRING, NULL, 1, 0); err = GetLastError(); - todo_wine ok(!ret && err == ERROR_INVALID_USER_BUFFER, "%lu != %d\n", err, ERROR_INVALID_USER_BUFFER); + ok(!ret && err == ERROR_INVALID_USER_BUFFER, "%lu != %d\n", err, ERROR_INVALID_USER_BUFFER);
ret = SetupDiSetDeviceInterfacePropertyW(set, &iface, &DEVPKEY_DeviceInterface_FriendlyName, DEVPROP_TYPE_STRING, (BYTE *)str, sizeof(str), 1); err = GetLastError(); - todo_wine ok(!ret && err == ERROR_INVALID_FLAGS, "%lu != %d\n", err, ERROR_INVALID_FLAGS); + ok(!ret && err == ERROR_INVALID_FLAGS, "%lu != %d\n", err, ERROR_INVALID_FLAGS);
ret = SetupDiGetDeviceInterfacePropertyW(NULL, NULL, NULL, NULL, NULL, 0, NULL, 0); err = GetLastError(); @@ -2815,7 +2815,7 @@ static void test_device_interface_properties(void) ret = SetupDiSetDeviceInterfacePropertyW(set, &iface, &DEVPKEY_DeviceInterface_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE *)str, sizeof(str), 0); err = GetLastError(); - todo_wine ok(ret, "SetupDiSetDeviceInterfacePropertyW failed: %lu\n", err); + ok(ret, "SetupDiSetDeviceInterfacePropertyW failed: %lu\n", err);
ret = SetupDiGetDeviceInterfacePropertyW(set, &iface, &DEVPKEY_DeviceInterface_FriendlyName, &type, NULL, 0, &req, 0); err = GetLastError(); @@ -2833,7 +2833,7 @@ static void test_device_interface_properties(void) ret = SetupDiSetDeviceInterfacePropertyW(set, &iface, &DEVPKEY_DeviceInterface_FriendlyName, DEVPROP_TYPE_EMPTY, NULL, 0, 0); err = GetLastError(); - todo_wine ok(ret, "SetupDiSetDeviceInterfacePropertyW failed: %lu\n", err); + ok(ret, "SetupDiSetDeviceInterfacePropertyW failed: %lu\n", err);
/* DEVPKEY_DeviceInterface_Enabled is a "special" key, as it does not seem to be actually stored in the registry. */ ret = SetupDiGetDeviceInterfacePropertyW(set, &iface, &DEVPKEY_DeviceInterface_Enabled, &type, (BYTE *)&boolean, @@ -2848,26 +2848,26 @@ static void test_device_interface_properties(void) ret = SetupDiSetDeviceInterfacePropertyW(set, &iface, &DEVPKEY_DeviceInterface_Enabled, DEVPROP_TYPE_BOOLEAN, (const BYTE *)&boolean, sizeof(boolean), 0); err = GetLastError(); - todo_wine ok(!ret && err == ERROR_ACCESS_DENIED, "%lu != %d\n", err, ERROR_ACCESS_DENIED); + ok(!ret && err == ERROR_ACCESS_DENIED, "%lu != %d\n", err, ERROR_ACCESS_DENIED);
/* Nor can it be set to anything that's not a DEVPROP_TYPE_BOOLEAN. */ ret = SetupDiSetDeviceInterfacePropertyW(set, &iface, &DEVPKEY_DeviceInterface_Enabled, DEVPROP_TYPE_STRING, (const BYTE *)str, sizeof(str), 0); err = GetLastError(); - todo_wine ok(!ret && err == ERROR_INVALID_DATA, "%lu != %d\n", err, ERROR_INVALID_DATA); + ok(!ret && err == ERROR_INVALID_DATA, "%lu != %d\n", err, ERROR_INVALID_DATA);
/* It can however, be "set" to to its current value, i.e whether the interface is enabled. This seems to be a no-op. */ boolean = DEVPROP_FALSE; ret = SetupDiSetDeviceInterfacePropertyW(set, &iface, &DEVPKEY_DeviceInterface_Enabled, DEVPROP_TYPE_BOOLEAN, (const BYTE *)&boolean, sizeof(boolean), 0); err = GetLastError(); - todo_wine ok(ret, "SetupDiGetDeviceInterfacePropertyW failed: %lu\n", err); + ok(ret, "SetupDiGetDeviceInterfacePropertyW failed: %lu\n", err);
boolean = 0xde; ret = SetupDiSetDeviceInterfacePropertyW(set, &iface, &DEVPKEY_DeviceInterface_Enabled, DEVPROP_TYPE_BOOLEAN, (const BYTE *)&boolean, sizeof(boolean), 0); err = GetLastError(); - todo_wine ok(!ret && err == ERROR_INVALID_DATA, "%lu != %d\n", err, ERROR_INVALID_DATA); + ok(!ret && err == ERROR_INVALID_DATA, "%lu != %d\n", err, ERROR_INVALID_DATA);
ret = SetupDiRemoveDeviceInterface(set, &iface); ok(ret, "Failed to remove device interface, error %#lx.\n", GetLastError());