[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