setupapi: Implement SetupDiSetDevicePropertyW.

Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zhiyi Zhang 2019-01-30 11:21:18 +08:00 committed by Alexandre Julliard
parent 5e2aac9977
commit afac1c405d
4 changed files with 266 additions and 1 deletions

View File

@ -327,6 +327,28 @@ static WCHAR *get_refstr_key_path(struct device_iface *iface)
return path;
}
static BOOL is_valid_property_type(DEVPROPTYPE prop_type)
{
DWORD type = prop_type & DEVPROP_MASK_TYPE;
DWORD typemod = prop_type & DEVPROP_MASK_TYPEMOD;
if (type > MAX_DEVPROP_TYPE)
return FALSE;
if (typemod > MAX_DEVPROP_TYPEMOD)
return FALSE;
if (typemod == DEVPROP_TYPEMOD_ARRAY
&& (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL || type == DEVPROP_TYPE_STRING
|| type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
return FALSE;
if (typemod == DEVPROP_TYPEMOD_LIST
&& !(type == DEVPROP_TYPE_STRING || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
return FALSE;
return TRUE;
}
static LPWSTR SETUPDI_CreateSymbolicLinkPath(LPCWSTR instanceId,
const GUID *InterfaceClassGuid, LPCWSTR ReferenceString)
{
@ -3410,6 +3432,85 @@ BOOL WINAPI SetupDiSetDeviceInstallParamsW(
return TRUE;
}
BOOL WINAPI SetupDiSetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data, const DEVPROPKEY *key,
DEVPROPTYPE type, const BYTE *buffer, DWORD size, DWORD flags)
{
static const WCHAR propertiesW[] = {'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', 0};
static const WCHAR formatW[] = {'\\', '%', '0', '4', 'X', 0};
struct device *device;
HKEY properties_hkey, property_hkey;
WCHAR property_hkey_path[44];
LSTATUS ls;
TRACE("%p %p %p %#x %p %d %#x\n", devinfo, device_data, key, type, buffer, size, flags);
if (!(device = get_device(devinfo, device_data)))
return FALSE;
if (!key || !is_valid_property_type(type)
|| (buffer && !size && !(type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL))
|| (buffer && size && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL)))
{
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
if (size && !buffer)
{
SetLastError(ERROR_INVALID_USER_BUFFER);
return FALSE;
}
if (flags)
{
SetLastError(ERROR_INVALID_FLAGS);
return FALSE;
}
ls = RegCreateKeyExW(device->key, propertiesW, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &properties_hkey, NULL);
if (ls)
{
SetLastError(ls);
return FALSE;
}
SETUPDI_GuidToString(&key->fmtid, property_hkey_path);
sprintfW(property_hkey_path + 38, formatW, key->pid);
if (type == DEVPROP_TYPE_EMPTY)
{
ls = RegDeleteKeyW(properties_hkey, property_hkey_path);
RegCloseKey(properties_hkey);
SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
return !ls;
}
else if (type == DEVPROP_TYPE_NULL)
{
if (!(ls = RegOpenKeyW(properties_hkey, property_hkey_path, &property_hkey)))
{
ls = RegDeleteValueW(property_hkey, NULL);
RegCloseKey(property_hkey);
}
RegCloseKey(properties_hkey);
SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
return !ls;
}
else
{
if (!(ls = RegCreateKeyExW(properties_hkey, property_hkey_path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL,
&property_hkey, NULL)))
{
ls = RegSetValueExW(property_hkey, NULL, 0, 0xffff0000 | (0xffff & type), buffer, size);
RegCloseKey(property_hkey);
}
RegCloseKey(properties_hkey);
SetLastError(ls);
return !ls;
}
}
static HKEY SETUPDI_OpenDevKey(struct device *device, REGSAM samDesired)
{
HKEY enumKey, key = INVALID_HANDLE_VALUE;

View File

@ -389,6 +389,7 @@
@ stdcall SetupDiSetClassInstallParamsW(ptr ptr ptr long)
@ stdcall SetupDiSetDeviceInstallParamsA(ptr ptr ptr)
@ stdcall SetupDiSetDeviceInstallParamsW(ptr ptr ptr)
@ stdcall SetupDiSetDevicePropertyW(ptr ptr ptr long ptr long long)
@ stdcall SetupDiSetDeviceRegistryPropertyA(ptr ptr long ptr long)
@ stdcall SetupDiSetDeviceRegistryPropertyW(ptr ptr long ptr long)
@ stub SetupDiSetDriverInstallParamsA

View File

@ -26,7 +26,8 @@
#include "wingdi.h"
#include "winuser.h"
#include "winreg.h"
#include "guiddef.h"
#include "initguid.h"
#include "devpkey.h"
#include "setupapi.h"
#include "cfgmgr32.h"
@ -37,6 +38,8 @@
static GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,0x00,0x11,0x95,0x5c,0x2b,0xdb}};
static GUID guid2 = {0x6a55b5a5, 0x3f65, 0x11db, {0xb7,0x04,0x00,0x11,0x95,0x5c,0x2b,0xdb}};
BOOL (WINAPI *pSetupDiSetDevicePropertyW)(HDEVINFO, PSP_DEVINFO_DATA, const DEVPROPKEY *, DEVPROPTYPE, const BYTE *, DWORD, DWORD);
static void test_create_device_list_ex(void)
{
static const WCHAR machine[] = { 'd','u','m','m','y',0 };
@ -342,6 +345,163 @@ static void test_device_info(void)
SetupDiDestroyDeviceInfoList(set);
}
static void test_device_property(void)
{
static const WCHAR valueW[] = {'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f', 0};
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
HMODULE hmod;
HDEVINFO set;
DWORD err;
BOOL ret;
hmod = LoadLibraryA("setupapi.dll");
pSetupDiSetDevicePropertyW = (void *)GetProcAddress(hmod, "SetupDiSetDevicePropertyW");
if (!pSetupDiSetDevicePropertyW)
{
win_skip("SetupDiSetDevicePropertyW() are only available on vista+, skipping tests.\n");
FreeLibrary(hmod);
return;
}
set = SetupDiCreateDeviceInfoList(&guid, NULL);
ok(set != INVALID_HANDLE_VALUE, "Failed to create device list, error %#x.\n", GetLastError());
ret = SetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid, NULL, NULL, 0, &device_data);
ok(ret, "Failed to create device, error %#x.\n", GetLastError());
/* SetupDiSetDevicePropertyW */
/* #1 Null device info list */
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(NULL, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE *)valueW, sizeof(valueW), 0);
err = GetLastError();
ok(!ret, "Expect failure\n");
ok(err == ERROR_INVALID_HANDLE, "Expect last error %#x, got %#x\n", ERROR_INVALID_HANDLE, err);
/* #2 Null device */
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, NULL, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE *)valueW, sizeof(valueW), 0);
err = GetLastError();
ok(!ret, "Expect failure\n");
ok(err == ERROR_INVALID_PARAMETER, "Expect last error %#x, got %#x\n", ERROR_INVALID_PARAMETER, err);
/* #3 Null property key pointer */
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, NULL, DEVPROP_TYPE_STRING, (const BYTE *)valueW, sizeof(valueW), 0);
err = GetLastError();
ok(!ret, "Expect failure\n");
ok(err == ERROR_INVALID_DATA, "Expect last error %#x, got %#x\n", ERROR_INVALID_DATA, err);
/* #4 Invalid property key type */
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, 0xffff, (const BYTE *)valueW, sizeof(valueW), 0);
err = GetLastError();
ok(!ret, "Expect failure\n");
ok(err == ERROR_INVALID_DATA, "Expect last error %#x, got %#x\n", ERROR_INVALID_DATA, err);
/* #5 Null buffer pointer */
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, NULL, sizeof(valueW), 0);
err = GetLastError();
ok(!ret, "Expect failure\n");
ok(err == ERROR_INVALID_USER_BUFFER, "Expect last error %#x, got %#x\n", ERROR_INVALID_USER_BUFFER, err);
/* #6 Zero buffer size */
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE *)valueW, 0, 0);
err = GetLastError();
ok(!ret, "Expect failure\n");
ok(err == ERROR_INVALID_DATA, "Expect last error %#x, got %#x\n", ERROR_INVALID_DATA, err);
/* #7 Flags not zero */
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE *)valueW, sizeof(valueW), 1);
err = GetLastError();
ok(!ret, "Expect failure\n");
ok(err == ERROR_INVALID_FLAGS, "Expect last error %#x, got %#x\n", ERROR_INVALID_FLAGS, err);
/* #8 Normal */
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE *)valueW, sizeof(valueW), 0);
err = GetLastError();
ok(ret, "Expect success\n");
ok(err == NO_ERROR, "Expect last error %#x, got %#x\n", NO_ERROR, err);
/* #9 Delete property with buffer not null */
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE *)valueW, sizeof(valueW), 0);
ok(ret, "Expect success\n");
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_EMPTY, (const BYTE *)valueW, 0, 0);
err = GetLastError();
ok(ret, "Expect success\n");
ok(err == NO_ERROR, "Expect last error %#x, got %#x\n", NO_ERROR, err);
/* #10 Delete property with size not zero */
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE *)valueW, sizeof(valueW), 0);
ok(ret, "Expect success\n");
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_EMPTY, NULL, sizeof(valueW), 0);
err = GetLastError();
ok(!ret, "Expect failure\n");
ok(err == ERROR_INVALID_USER_BUFFER, "Expect last error %#x, got %#x\n", ERROR_INVALID_USER_BUFFER, err);
/* #11 Delete property */
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE *)valueW, sizeof(valueW), 0);
ok(ret, "Expect success\n");
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_EMPTY, NULL, 0, 0);
err = GetLastError();
ok(ret, "Expect success\n");
ok(err == NO_ERROR, "Expect last error %#x, got %#x\n", NO_ERROR, err);
/* #12 Delete non-existent property */
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_EMPTY, NULL, 0, 0);
err = GetLastError();
ok(!ret, "Expect failure\n");
ok(err == ERROR_NOT_FOUND, "Expect last error %#x, got %#x\n", ERROR_NOT_FOUND, err);
/* #13 Delete property value with buffer not null */
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE *)valueW, sizeof(valueW), 0);
ok(ret, "Expect success\n");
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_NULL, (const BYTE *)valueW, 0, 0);
err = GetLastError();
ok(ret, "Expect success\n");
ok(err == NO_ERROR, "Expect last error %#x, got %#x\n", NO_ERROR, err);
/* #14 Delete property value with size not zero */
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE *)valueW, sizeof(valueW), 0);
ok(ret, "Expect success\n");
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_NULL, NULL, sizeof(valueW), 0);
err = GetLastError();
ok(!ret, "Expect failure\n");
ok(err == ERROR_INVALID_USER_BUFFER, "Expect last error %#x, got %#x\n", ERROR_INVALID_USER_BUFFER, err);
/* #15 Delete property value */
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE *)valueW, sizeof(valueW), 0);
ok(ret, "Expect success\n");
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_NULL, NULL, 0, 0);
err = GetLastError();
ok(ret, "Expect success\n");
ok(err == NO_ERROR, "Expect last error %#x, got %#x\n", NO_ERROR, err);
/* #16 Delete non-existent property value */
SetLastError(0xdeadbeef);
ret = pSetupDiSetDevicePropertyW(set, &device_data, &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_NULL, NULL, 0, 0);
err = GetLastError();
ok(!ret, "Expect failure\n");
ok(err == ERROR_NOT_FOUND, "Expect last error %#x, got %#x\n", ERROR_NOT_FOUND, err);
ret = SetupDiRemoveDevice(set, &device_data);
ok(ret, "Got unexpected error %#x.\n", GetLastError());
SetupDiDestroyDeviceInfoList(set);
FreeLibrary(hmod);
}
static void test_get_device_instance_id(void)
{
BOOL ret;
@ -1339,6 +1499,7 @@ START_TEST(devinst)
test_open_class_key();
test_install_class();
test_device_info();
test_device_property();
test_get_device_instance_id();
test_register_device_info();
test_device_iface();

View File

@ -1634,6 +1634,8 @@ BOOL WINAPI SetupDiSetDeviceInterfaceDefault(HDEVINFO, PSP_DEVICE_INTERFACE_
BOOL WINAPI SetupDiSetDeviceInstallParamsA(HDEVINFO, PSP_DEVINFO_DATA, PSP_DEVINSTALL_PARAMS_A);
BOOL WINAPI SetupDiSetDeviceInstallParamsW(HDEVINFO, PSP_DEVINFO_DATA, PSP_DEVINSTALL_PARAMS_W);
#define SetupDiSetDeviceInstallParams WINELIB_NAME_AW(SetupDiSetDeviceInstallParams)
BOOL WINAPI SetupDiSetDevicePropertyW(HDEVINFO, PSP_DEVINFO_DATA, const DEVPROPKEY *, DEVPROPTYPE, const BYTE *, DWORD, DWORD);
#define SetupDiSetDeviceProperty WINELIB_NAME_AW(SetupDiSetDeviceProperty) /* note: A function doesn't exist */
BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(HDEVINFO, PSP_DEVINFO_DATA, DWORD, const BYTE *, DWORD);
BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(HDEVINFO, PSP_DEVINFO_DATA, DWORD, const BYTE *, DWORD);
#define SetupDiSetDeviceRegistryProperty WINELIB_NAME_AW(SetupDiSetDeviceRegistryProperty)