[RFC PATCH 2/9] setupapi: Implement SetupDiSetDevicePropertyW.

Zebediah Figura z.figura12 at gmail.com
Tue Jan 22 20:17:54 CST 2019


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?

>   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?

> +
> +    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.

> +    }
> +    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