[RFC PATCH 2/9] setupapi: Implement SetupDiSetDevicePropertyW.
Zhiyi Zhang
zzhang at codeweavers.com
Wed Jan 23 01:39:10 CST 2019
On 23/01/2019 10:17, Zebediah Figura wrote:
> On 12/18/18 10:20 AM, Zhiyi Zhang wrote:
>> Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
>> ---
>> dlls/setupapi/devinst.c | 139 ++++++++++++++++++++++++
>> dlls/setupapi/setupapi.spec | 2 +-
>> dlls/setupapi/tests/devinst.c | 194 +++++++++++++++++++++++++++++++++-
>> include/setupapi.h | 2 +
>> 4 files changed, 335 insertions(+), 2 deletions(-)
>>
>> diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c
>> index 55746562c8..556bba4684 100644
>> --- a/dlls/setupapi/devinst.c
>> +++ b/dlls/setupapi/devinst.c
>> @@ -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;
>> +}
>> +
>
> This level of extensive error checking is probably not a bad idea,
> but—the current state of most of SetupDi notwithstanding—I'm not sure
> it's a good one either (and it's certainly a little troublesome to
> review). I won't stand opposed to it if pressed, but is it really
> necessary?
I would rather do the extensive error/parameter checking now than fixing
the crash caused by not checking later. I feel like there are already so
many bugs because of not enough checking.
As long as they are covered by tests. They shouldn't be too much an issue.
>
>> static LPWSTR SETUPDI_CreateSymbolicLinkPath(LPCWSTR instanceId,
>> const GUID *InterfaceClassGuid, LPCWSTR ReferenceString)
>> {
>> @@ -3343,6 +3365,123 @@ BOOL WINAPI SetupDiSetDeviceInstallParamsW(
>> return TRUE;
>> }
>> +BOOL WINAPI SetupDiSetDevicePropertyW(HDEVINFO devinfo,
>> PSP_DEVINFO_DATA devinfo_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, devinfo_data, key,
>> type, buffer, size, flags);
>> +
>> + if (!(device = get_device(devinfo, devinfo_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;
>> + }
>> +
>> + if (key->pid < 2)
>> + {
>> + SetLastError(ERROR_INVALID_REG_PROPERTY);
>> + return FALSE;
>> + }
>
> As above.
>
>> +
>> + ls = RegCreateKeyExW(device->key, propertiesW, 0, NULL, 0,
>> KEY_READ | KEY_WRITE, NULL, &properties_hkey, NULL);
>> + if (ls)
>> + {
>> + SetLastError(ls);
>> + return FALSE;
>> + }
>
> As long as we're not using this key directly, couldn't we just put
> "Properties" into the format string, and get rid of properties_hkey?
Sure.
>
>> +
>> + SETUPDI_GuidToString(&key->fmtid, property_hkey_path);
>> + sprintfW(property_hkey_path + 38, formatW, key->pid);
>> +
>> + if (type == DEVPROP_TYPE_EMPTY)
>> + {
>> + if (RegDeleteKeyW(properties_hkey, property_hkey_path))
>> + {
>> + RegCloseKey(properties_hkey);
>> + SetLastError(ERROR_NOT_FOUND);
>> + return FALSE;
>> + }
>> + else
>> + {
>> + RegCloseKey(properties_hkey);
>> + SetLastError(NO_ERROR);
>> + return TRUE;
>> + }
>
> Some of the branches in this patch are a bit redundant. For example,
> the above could be:
>
> ls = RegDeleteKeyW(properties_hkey, property_hkey_path);
> RegCloseKey(properties_hkey);
> SetLastError(ls);
> return !ls;
>
> which feels simpler and more readable to me.
Thanks.
>
>> + }
>> + else if (type == DEVPROP_TYPE_NULL)
>> + {
>> + if (RegOpenKeyW(properties_hkey, property_hkey_path,
>> &property_hkey))
>> + {
>> + RegCloseKey(properties_hkey);
>> + SetLastError(ERROR_NOT_FOUND);
>> + return FALSE;
>> + }
>> +
>> + if (RegDeleteValueW(property_hkey, NULL))
>> + {
>> + RegCloseKey(property_hkey);
>> + RegCloseKey(properties_hkey);
>> + SetLastError(ERROR_NOT_FOUND);
>> + return FALSE;
>> + }
>> + else
>> + {
>> + RegCloseKey(property_hkey);
>> + RegCloseKey(properties_hkey);
>> + SetLastError(NO_ERROR);
>> + return TRUE;
>> + }
>> + }
>> + else
>> + {
>> + if ((ls = RegCreateKeyExW(properties_hkey,
>> property_hkey_path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL,
>> + &property_hkey, NULL)))
>> + {
>> + RegCloseKey(properties_hkey);
>> + SetLastError(ls);
>> + return FALSE;
>> + }
>> +
>> + if ((ls = RegSetValueExW(property_hkey, NULL, 0, 0xffff0000
>> | (0xffff & type), buffer, size)))
>> + {
>> + RegCloseKey(property_hkey);
>> + RegCloseKey(properties_hkey);
>> + SetLastError(ls);
>> + return FALSE;
>> + }
>> + else
>> + {
>> + RegCloseKey(property_hkey);
>> + RegCloseKey(properties_hkey);
>> + SetLastError(NO_ERROR);
>> + return TRUE;
>> + }
>> + }
>> +}
>> +
>> static HKEY SETUPDI_OpenDevKey(struct device *device, REGSAM
>> samDesired)
>> {
>> HKEY enumKey, key = INVALID_HANDLE_VALUE;
>> diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec
>> index eb2dab204d..fb44298292 100644
>> --- a/dlls/setupapi/setupapi.spec
>> +++ b/dlls/setupapi/setupapi.spec
>> @@ -475,7 +475,7 @@
>> @ stdcall SetupDiSetDeviceInstallParamsW(ptr ptr ptr)
>> @ stub SetupDiSetDeviceInterfaceDefault
>> @ stub SetupDiSetDeviceInterfacePropertyW
>> -@ stub SetupDiSetDevicePropertyW
>> +@ 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
>> diff --git a/dlls/setupapi/tests/devinst.c
>> b/dlls/setupapi/tests/devinst.c
>> index bfffcb9c32..274c28745c 100644
>> --- a/dlls/setupapi/tests/devinst.c
>> +++ b/dlls/setupapi/tests/devinst.c
>> @@ -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 LSTATUS devinst_RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
>> {
>> LONG ret;
>> @@ -408,6 +411,194 @@ 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};
>> + HMODULE hmod;
>> + HDEVINFO set;
>> + SP_DEVINFO_DATA device = {sizeof(device)};
>> + DEVPROPKEY key;
>> + 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);
>> + ok(ret, "Failed to create device, error %#x.\n", GetLastError());
>> +
>> + /* SetupDiSetDevicePropertyW */
>> + /* #1 Null device info list */
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(NULL, &device,
>> &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);
>
> As above, exhaustive invalid-parameter tests seem unnecessary,
> especially when some fail (e.g. #8 below).
>
>> +
>> + /* #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, 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,
>> &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,
>> &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,
>> &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,
>> &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 Invalid key pid */
>> + key.fmtid = DEVPKEY_Device_FriendlyName.fmtid;
>> + key.pid = 0;
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(set, &device, &key,
>> DEVPROP_TYPE_STRING, (const BYTE *)valueW, sizeof(valueW), 0);
>> + err = GetLastError();
>> + /* Failure on win8+ */
>> + if(0) ok(ret, "Expect success\n");
>> + ok(err == ERROR_INVALID_REG_PROPERTY || broken(err == NO_ERROR),
>> "Expect last error %#x, got %#x\n", ERROR_INVALID_REG_PROPERTY, err);
>> +
>> + /* #9 Normal */
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &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);
>> +
>> + /* #10 Delete property with buffer not null and size not zero */
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE
>> *)valueW, sizeof(valueW), 0);
>> + ok(ret, "Expect success\n");
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_EMPTY, (const BYTE
>> *)valueW, sizeof(valueW), 0);
>> + err = GetLastError();
>> + /* Failure on win8+ */
>> + if(0) ok(!ret, "Expect failure\n");
>> + ok(err == ERROR_INVALID_DATA || broken(err == NO_ERROR), "Expect
>> last error %#x, got %#x\n", ERROR_INVALID_DATA, err);
>> +
>> + /* #11 Delete property with buffer not null */
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE
>> *)valueW, sizeof(valueW), 0);
>> + ok(ret, "Expect success\n");
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &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);
>> +
>> + /* #12 Delete property with size not zero */
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE
>> *)valueW, sizeof(valueW), 0);
>> + ok(ret, "Expect success\n");
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &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);
>> +
>> + /* #13 Delete property */
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE
>> *)valueW, sizeof(valueW), 0);
>> + ok(ret, "Expect success\n");
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &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);
>> +
>> + /* #14 Delete non-existent property */
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &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);
>> +
>> + /* #15 Delete property value with buffer not null and size not
>> zero */
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE
>> *)valueW, sizeof(valueW), 0);
>> + ok(ret, "Expect success\n");
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_NULL, (const BYTE
>> *)valueW, sizeof(valueW), 0);
>> + err = GetLastError();
>> + /* Failure on win8+ */
>> + if(0) ok(!ret, "Expect failure\n");
>> + ok(err == ERROR_INVALID_DATA || broken(err == NO_ERROR), "Expect
>> last error %#x, got %#x\n", ERROR_INVALID_DATA, err);
>> +
>> + /* #16 Delete property value with buffer not null */
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE
>> *)valueW, sizeof(valueW), 0);
>> + ok(ret, "Expect success\n");
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &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);
>> +
>> + /* #17 Delete property value with size not zero */
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE
>> *)valueW, sizeof(valueW), 0);
>> + ok(ret, "Expect success\n");
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &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);
>> +
>> + /* #18 Delete property value */
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &DEVPKEY_Device_FriendlyName, DEVPROP_TYPE_STRING, (const BYTE
>> *)valueW, sizeof(valueW), 0);
>> + ok(ret, "Expect success\n");
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &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);
>> +
>> + /* #19 Delete non-existent property value */
>> + SetLastError(0xdeadbeef);
>> + ret = pSetupDiSetDevicePropertyW(set, &device,
>> &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);
>> + ok(ret, "Got unexpected error %#x.\n", GetLastError());
>> +
>> + SetupDiDestroyDeviceInfoList(set);
>> + FreeLibrary(hmod);
>> +}
>> +
>> static void test_get_device_instance_id(void)
>> {
>> BOOL ret;
>> @@ -1366,6 +1557,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();
>> diff --git a/include/setupapi.h b/include/setupapi.h
>> index 76e255cc44..4491617d8a 100644
>> --- a/include/setupapi.h
>> +++ b/include/setupapi.h
>> @@ -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)
>>
>
>
>
More information about the wine-devel
mailing list