setupapi: Implement SetupDiSetDevicePropertyW.
Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5e2aac9977
commit
afac1c405d
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue