From 33b1d8feaeded3b5375c9cc820189d889f2a0842 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Wed, 19 Sep 2007 17:50:17 -0700 Subject: [PATCH] Implement SetupDiCreateDeviceInfoW --- dlls/setupapi/devinst.c | 203 ++++++++++++++++++++++++++++++++++++++--- dlls/setupapi/tests/devinst.c | 7 - 2 files changed, 189 insertions(+), 21 deletions(-) diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index a1c27dd..95d45ae 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -81,6 +81,78 @@ struct DeviceInfoSet 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.@) * @@ -740,6 +812,28 @@ BOOL WINAPI SetupDiCreateDeviceInfoA( 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 <<= 8; + devInst |= *ptr - '0'; + ptr++; + } + else + valid = FALSE; + } + TRACE("%d\n", valid ? devInst : 0xffffffff); + return valid ? devInst : 0xffffffff; +} + /*********************************************************************** * SetupDiCreateDeviceInfoW (SETUPAPI.@) */ @@ -753,7 +847,8 @@ BOOL WINAPI SetupDiCreateDeviceInfoW( PSP_DEVINFO_DATA DeviceInfoData) { 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), debugstr_guid(ClassGuid), debugstr_w(DeviceDescription), @@ -774,26 +869,101 @@ BOOL WINAPI SetupDiCreateDeviceInfoW( SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - if (set->magic == SETUP_DEVICE_INFO_SET_MAGIC) + if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC) { - if (IsEqualGUID(&set->ClassGuid, &GUID_NULL) || - IsEqualGUID(ClassGuid, &set->ClassGuid)) - ret = TRUE; + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && + !IsEqualGUID(ClassGuid, &set->ClassGuid)) + { + SetLastError(ERROR_CLASS_MISMATCH); + return FALSE; + } + if ((CreationFlags & DICD_GENERATE_ID)) + { + if (strchrW(DeviceName, '\\')) + SetLastError(ERROR_INVALID_DEVINST_NAME); else - SetLastError(ERROR_CLASS_MISMATCH); - if ((CreationFlags & DICD_GENERATE_ID) && strchrW(DeviceName, '\\')) { - SetLastError(ERROR_INVALID_DEVINST_NAME); - ret = FALSE; + static const WCHAR newDeviceFmt[] = {'R','o','o','t','\\','%','s', + '\\','%','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; + /* 11 == lstrlenW(L"Root\\") + lstrlenW("\\0000") + 1 */ + instanceId = HeapAlloc(GetProcessHeap(), 0, + (11 + lstrlenW(DeviceName)) * sizeof(WCHAR)); + if (instanceId) + { + sprintfW((LPWSTR)instanceId, newDeviceFmt, DeviceName, + devId); + allocatedInstanceId = TRUE; + ret = TRUE; + } + else + ret = FALSE; } - if (ret) + } + else + { + DWORD i; + + ret = TRUE; + instanceId = DeviceName; + for (i = 0; ret && i < set->cDevices; i++) { - FIXME("stub\n"); - ret = FALSE; + struct DeviceInfo *devInfo = + (struct DeviceInfo *)set->devices[i].Reserved; + + if (!lstrcmpW(DeviceName, devInfo->instanceId)) + { + SetLastError(ERROR_DEVINST_ALREADY_EXISTS); + ret = FALSE; + } } } - else - SetLastError(ERROR_INVALID_HANDLE); + 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; } @@ -1211,6 +1381,11 @@ BOOL WINAPI SetupDiDestroyDeviceInfoList 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); ret = TRUE; diff --git a/dlls/setupapi/tests/devinst.c b/dlls/setupapi/tests/devinst.c index 05d42d8..28e2624 100644 --- a/dlls/setupapi/tests/devinst.c +++ b/dlls/setupapi/tests/devinst.c @@ -169,27 +169,23 @@ static void testCreateDeviceInfo(void) /* Finally, with all three required parameters, this succeeds: */ ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid, NULL, NULL, 0, NULL); - todo_wine ok(ret, "pSetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); /* This fails because the device ID already exists.. */ SetLastError(0xdeadbeef); ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid, NULL, NULL, 0, &devInfo); - todo_wine ok(!ret && GetLastError() == ERROR_DEVINST_ALREADY_EXISTS, "Expected ERROR_DEVINST_ALREADY_EXISTS, got %08x\n", GetLastError()); /* whereas this "fails" because cbSize is wrong.. */ SetLastError(0xdeadbeef); ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL, DICD_GENERATE_ID, &devInfo); - todo_wine ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER, "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError()); devInfo.cbSize = sizeof(devInfo); ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL, DICD_GENERATE_ID, &devInfo); /* and this finally succeeds. */ - todo_wine ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); /* There were three devices added, however - the second failure just * resulted in the SP_DEVINFO_DATA not getting copied. @@ -198,7 +194,6 @@ static void testCreateDeviceInfo(void) i = 0; while (pSetupDiEnumDeviceInfo(set, i, &devInfo)) i++; - todo_wine ok(i == 3, "Expected 3 devices, got %d\n", i); ok(GetLastError() == ERROR_NO_MORE_ITEMS, "SetupDiEnumDeviceInfo failed: %08x\n", GetLastError()); @@ -261,7 +256,6 @@ static void testGetDeviceInstanceId(void "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid, NULL, NULL, 0, &devInfo); - todo_wine ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); SetLastError(0xdeadbeef); ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size); @@ -277,7 +271,6 @@ static void testGetDeviceInstanceId(void "Unexpected instance ID %s\n", instanceID); ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL, DICD_GENERATE_ID, &devInfo); - todo_wine ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID, sizeof(instanceID), NULL); -- 1.4.1