setupapi: Implement SetupDiCreateDeviceInfoW.
This commit is contained in:
parent
ac7e221c20
commit
83f05e79bb
|
@ -81,6 +81,78 @@ struct DeviceInfoSet
|
||||||
SP_DEVINFO_DATA *devices;
|
SP_DEVINFO_DATA *devices;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Pointed to by SP_DEVINFO_DATA's Reserved member */
|
||||||
|
struct DeviceInfo
|
||||||
|
{
|
||||||
|
LPWSTR instanceId;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct DeviceInfo *SETUPDI_AllocateDeviceInfo(LPCWSTR instanceId)
|
||||||
|
{
|
||||||
|
struct DeviceInfo *devInfo = HeapAlloc(GetProcessHeap(), 0,
|
||||||
|
sizeof(struct DeviceInfo));
|
||||||
|
|
||||||
|
if (devInfo)
|
||||||
|
{
|
||||||
|
devInfo->instanceId = HeapAlloc(GetProcessHeap(), 0,
|
||||||
|
(lstrlenW(instanceId) + 1) * sizeof(WCHAR));
|
||||||
|
if (devInfo->instanceId)
|
||||||
|
lstrcpyW(devInfo->instanceId, instanceId);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, devInfo);
|
||||||
|
devInfo = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return devInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SETUPDI_FreeDeviceInfo(struct DeviceInfo *devInfo)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, devInfo->instanceId);
|
||||||
|
HeapFree(GetProcessHeap(), 0, devInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adds a device with GUID guid and identifer devInst to set. Allocates a
|
||||||
|
* struct DeviceInfo, and points the returned device info's Reserved member
|
||||||
|
* to it.
|
||||||
|
* Returns a pointer to the newly allocated device info.
|
||||||
|
*/
|
||||||
|
static BOOL SETUPDI_AddDeviceToSet(struct DeviceInfoSet *set,
|
||||||
|
const GUID *guid,
|
||||||
|
DWORD devInst,
|
||||||
|
LPCWSTR instanceId,
|
||||||
|
SP_DEVINFO_DATA **dev)
|
||||||
|
{
|
||||||
|
BOOL ret = FALSE;
|
||||||
|
struct DeviceInfo *devInfo = SETUPDI_AllocateDeviceInfo(instanceId);
|
||||||
|
|
||||||
|
if (devInfo)
|
||||||
|
{
|
||||||
|
if (set->devices)
|
||||||
|
set->devices = HeapReAlloc(GetProcessHeap(), 0, set->devices,
|
||||||
|
(set->cDevices + 1) * sizeof(SP_DEVINFO_DATA));
|
||||||
|
else
|
||||||
|
set->devices = HeapAlloc(GetProcessHeap(), 0,
|
||||||
|
sizeof(SP_DEVINFO_DATA));
|
||||||
|
if (set->devices)
|
||||||
|
{
|
||||||
|
*dev = &set->devices[set->cDevices++];
|
||||||
|
(*dev)->cbSize = sizeof(SP_DEVINFO_DATA);
|
||||||
|
memcpy(&(*dev)->ClassGuid, guid, sizeof(GUID));
|
||||||
|
(*dev)->DevInst = devInst;
|
||||||
|
(*dev)->Reserved = (ULONG_PTR)devInfo;
|
||||||
|
ret = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, devInfo);
|
||||||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* SetupDiBuildClassInfoList (SETUPAPI.@)
|
* SetupDiBuildClassInfoList (SETUPAPI.@)
|
||||||
*
|
*
|
||||||
|
@ -740,6 +812,28 @@ BOOL WINAPI SetupDiCreateDeviceInfoA(
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DWORD SETUPDI_DevNameToDevID(LPCWSTR devName)
|
||||||
|
{
|
||||||
|
LPCWSTR ptr;
|
||||||
|
DWORD devNameLen = lstrlenW(devName), devInst = 0;
|
||||||
|
BOOL valid = TRUE;
|
||||||
|
|
||||||
|
TRACE("%s\n", debugstr_w(devName));
|
||||||
|
for (ptr = devName; valid && *ptr && ptr - devName < devNameLen; )
|
||||||
|
{
|
||||||
|
if (isdigitW(*ptr))
|
||||||
|
{
|
||||||
|
devInst *= 10;
|
||||||
|
devInst |= *ptr - '0';
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
valid = FALSE;
|
||||||
|
}
|
||||||
|
TRACE("%d\n", valid ? devInst : 0xffffffff);
|
||||||
|
return valid ? devInst : 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* SetupDiCreateDeviceInfoW (SETUPAPI.@)
|
* SetupDiCreateDeviceInfoW (SETUPAPI.@)
|
||||||
*/
|
*/
|
||||||
|
@ -753,7 +847,8 @@ BOOL WINAPI SetupDiCreateDeviceInfoW(
|
||||||
PSP_DEVINFO_DATA DeviceInfoData)
|
PSP_DEVINFO_DATA DeviceInfoData)
|
||||||
{
|
{
|
||||||
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
|
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE, allocatedInstanceId = FALSE;
|
||||||
|
LPCWSTR instanceId = NULL;
|
||||||
|
|
||||||
TRACE("%p %s %s %s %p %x %p\n", DeviceInfoSet, debugstr_w(DeviceName),
|
TRACE("%p %s %s %s %p %x %p\n", DeviceInfoSet, debugstr_w(DeviceName),
|
||||||
debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
|
debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
|
||||||
|
@ -774,26 +869,101 @@ BOOL WINAPI SetupDiCreateDeviceInfoW(
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (set->magic == SETUP_DEVICE_INFO_SET_MAGIC)
|
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
|
||||||
{
|
{
|
||||||
if (IsEqualGUID(&set->ClassGuid, &GUID_NULL) ||
|
SetLastError(ERROR_INVALID_HANDLE);
|
||||||
IsEqualGUID(ClassGuid, &set->ClassGuid))
|
return FALSE;
|
||||||
ret = TRUE;
|
}
|
||||||
else
|
if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) &&
|
||||||
SetLastError(ERROR_CLASS_MISMATCH);
|
!IsEqualGUID(ClassGuid, &set->ClassGuid))
|
||||||
if ((CreationFlags & DICD_GENERATE_ID) && strchrW(DeviceName, '\\'))
|
{
|
||||||
{
|
SetLastError(ERROR_CLASS_MISMATCH);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if ((CreationFlags & DICD_GENERATE_ID))
|
||||||
|
{
|
||||||
|
if (strchrW(DeviceName, '\\'))
|
||||||
SetLastError(ERROR_INVALID_DEVINST_NAME);
|
SetLastError(ERROR_INVALID_DEVINST_NAME);
|
||||||
ret = FALSE;
|
else
|
||||||
}
|
|
||||||
if (ret)
|
|
||||||
{
|
{
|
||||||
FIXME("stub\n");
|
static const WCHAR newDeviceFmt[] = {'R','o','o','t','\\','%','s',
|
||||||
ret = FALSE;
|
'\\','%','0','4','d',0};
|
||||||
|
DWORD devId;
|
||||||
|
|
||||||
|
if (set->cDevices)
|
||||||
|
{
|
||||||
|
DWORD i, highestDevID = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < set->cDevices; i++)
|
||||||
|
{
|
||||||
|
struct DeviceInfo *devInfo =
|
||||||
|
(struct DeviceInfo *)set->devices[i].Reserved;
|
||||||
|
LPCWSTR devName = strrchrW(devInfo->instanceId, '\\');
|
||||||
|
DWORD id;
|
||||||
|
|
||||||
|
if (devName)
|
||||||
|
devName++;
|
||||||
|
else
|
||||||
|
devName = devInfo->instanceId;
|
||||||
|
id = SETUPDI_DevNameToDevID(devName);
|
||||||
|
if (id != 0xffffffff && id > highestDevID)
|
||||||
|
highestDevID = id;
|
||||||
|
}
|
||||||
|
devId = highestDevID + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
devId = 0;
|
||||||
|
/* 17 == lstrlenW(L"Root\\") + lstrlenW("\\") + 1 + %d max size */
|
||||||
|
instanceId = HeapAlloc(GetProcessHeap(), 0,
|
||||||
|
(17 + lstrlenW(DeviceName)) * sizeof(WCHAR));
|
||||||
|
if (instanceId)
|
||||||
|
{
|
||||||
|
sprintfW((LPWSTR)instanceId, newDeviceFmt, DeviceName,
|
||||||
|
devId);
|
||||||
|
allocatedInstanceId = TRUE;
|
||||||
|
ret = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SetLastError(ERROR_INVALID_HANDLE);
|
{
|
||||||
|
DWORD i;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
instanceId = DeviceName;
|
||||||
|
for (i = 0; ret && i < set->cDevices; i++)
|
||||||
|
{
|
||||||
|
struct DeviceInfo *devInfo =
|
||||||
|
(struct DeviceInfo *)set->devices[i].Reserved;
|
||||||
|
|
||||||
|
if (!lstrcmpW(DeviceName, devInfo->instanceId))
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
SP_DEVINFO_DATA *dev = NULL;
|
||||||
|
|
||||||
|
ret = SETUPDI_AddDeviceToSet(set, ClassGuid, 0 /* FIXME: DevInst */,
|
||||||
|
instanceId, &dev);
|
||||||
|
if (ret && DeviceInfoData)
|
||||||
|
{
|
||||||
|
if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy(DeviceInfoData, dev, sizeof(SP_DEVINFO_DATA));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allocatedInstanceId)
|
||||||
|
HeapFree(GetProcessHeap(), 0, (LPWSTR)instanceId);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1211,6 +1381,11 @@ BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
|
||||||
|
|
||||||
if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
|
if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
|
||||||
{
|
{
|
||||||
|
DWORD i;
|
||||||
|
|
||||||
|
for (i = 0; i < list->cDevices; i++)
|
||||||
|
SETUPDI_FreeDeviceInfo(
|
||||||
|
(struct DeviceInfo *)list->devices[i].Reserved);
|
||||||
HeapFree(GetProcessHeap(), 0, list->devices);
|
HeapFree(GetProcessHeap(), 0, list->devices);
|
||||||
HeapFree(GetProcessHeap(), 0, list);
|
HeapFree(GetProcessHeap(), 0, list);
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
|
|
|
@ -169,27 +169,23 @@ static void testCreateDeviceInfo(void)
|
||||||
/* Finally, with all three required parameters, this succeeds: */
|
/* Finally, with all three required parameters, this succeeds: */
|
||||||
ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
|
ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
|
||||||
NULL, NULL, 0, NULL);
|
NULL, NULL, 0, NULL);
|
||||||
todo_wine
|
|
||||||
ok(ret, "pSetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
|
ok(ret, "pSetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
|
||||||
/* This fails because the device ID already exists.. */
|
/* This fails because the device ID already exists.. */
|
||||||
SetLastError(0xdeadbeef);
|
SetLastError(0xdeadbeef);
|
||||||
ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
|
ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
|
||||||
NULL, NULL, 0, &devInfo);
|
NULL, NULL, 0, &devInfo);
|
||||||
todo_wine
|
|
||||||
ok(!ret && GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
|
ok(!ret && GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
|
||||||
"Expected ERROR_DEVINST_ALREADY_EXISTS, got %08x\n", GetLastError());
|
"Expected ERROR_DEVINST_ALREADY_EXISTS, got %08x\n", GetLastError());
|
||||||
/* whereas this "fails" because cbSize is wrong.. */
|
/* whereas this "fails" because cbSize is wrong.. */
|
||||||
SetLastError(0xdeadbeef);
|
SetLastError(0xdeadbeef);
|
||||||
ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
|
ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
|
||||||
DICD_GENERATE_ID, &devInfo);
|
DICD_GENERATE_ID, &devInfo);
|
||||||
todo_wine
|
|
||||||
ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
|
ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
|
||||||
"Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
|
"Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
|
||||||
devInfo.cbSize = sizeof(devInfo);
|
devInfo.cbSize = sizeof(devInfo);
|
||||||
ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
|
ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
|
||||||
DICD_GENERATE_ID, &devInfo);
|
DICD_GENERATE_ID, &devInfo);
|
||||||
/* and this finally succeeds. */
|
/* and this finally succeeds. */
|
||||||
todo_wine
|
|
||||||
ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
|
ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
|
||||||
/* There were three devices added, however - the second failure just
|
/* There were three devices added, however - the second failure just
|
||||||
* resulted in the SP_DEVINFO_DATA not getting copied.
|
* resulted in the SP_DEVINFO_DATA not getting copied.
|
||||||
|
@ -198,7 +194,6 @@ static void testCreateDeviceInfo(void)
|
||||||
i = 0;
|
i = 0;
|
||||||
while (pSetupDiEnumDeviceInfo(set, i, &devInfo))
|
while (pSetupDiEnumDeviceInfo(set, i, &devInfo))
|
||||||
i++;
|
i++;
|
||||||
todo_wine
|
|
||||||
ok(i == 3, "Expected 3 devices, got %d\n", i);
|
ok(i == 3, "Expected 3 devices, got %d\n", i);
|
||||||
ok(GetLastError() == ERROR_NO_MORE_ITEMS,
|
ok(GetLastError() == ERROR_NO_MORE_ITEMS,
|
||||||
"SetupDiEnumDeviceInfo failed: %08x\n", GetLastError());
|
"SetupDiEnumDeviceInfo failed: %08x\n", GetLastError());
|
||||||
|
@ -261,7 +256,6 @@ static void testGetDeviceInstanceId(void)
|
||||||
"Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
|
"Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
|
||||||
ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
|
ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
|
||||||
NULL, NULL, 0, &devInfo);
|
NULL, NULL, 0, &devInfo);
|
||||||
todo_wine
|
|
||||||
ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
|
ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
|
||||||
SetLastError(0xdeadbeef);
|
SetLastError(0xdeadbeef);
|
||||||
ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
|
ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
|
||||||
|
@ -277,7 +271,6 @@ static void testGetDeviceInstanceId(void)
|
||||||
"Unexpected instance ID %s\n", instanceID);
|
"Unexpected instance ID %s\n", instanceID);
|
||||||
ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid,
|
ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid,
|
||||||
NULL, NULL, DICD_GENERATE_ID, &devInfo);
|
NULL, NULL, DICD_GENERATE_ID, &devInfo);
|
||||||
todo_wine
|
|
||||||
ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
|
ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
|
||||||
ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID,
|
ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID,
|
||||||
sizeof(instanceID), NULL);
|
sizeof(instanceID), NULL);
|
||||||
|
|
Loading…
Reference in New Issue