From 5e12d1ff72c8db0df70cc425835abf34470c8b78 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Fri, 21 Sep 2007 11:36:12 -0700 Subject: [PATCH] Implement SetupDiCreateDeviceInterfaceW --- dlls/setupapi/devinst.c | 259 ++++++++++++++++++++++++++++++++++++++++- dlls/setupapi/tests/devinst.c | 3 2 files changed, 253 insertions(+), 9 deletions(-) diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 43254f7..b00e901 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -99,14 +99,240 @@ struct DeviceInfoSet SP_DEVINFO_DATA *devices; }; +/* Pointed to by SP_DEVICE_INTERFACE_DATA's Reserved member */ +struct InterfaceInfo +{ + LPWSTR referenceString; +}; + +/* A device may have multiple instances of the same interface, so this holds + * each instance belonging to a particular interface. + */ +struct InterfaceInstances +{ + GUID guid; + DWORD cInstances; + DWORD cInstancesAllocated; + SP_DEVICE_INTERFACE_DATA *instances; +}; + /* Pointed to by SP_DEVINFO_DATA's Reserved member */ struct DeviceInfo { - HKEY key; - BOOL phantom; - LPWSTR instanceId; + HKEY key; + BOOL phantom; + LPWSTR instanceId; + DWORD cInterfaces; + DWORD cInterfacesAllocated; + struct InterfaceInstances *interfaces; }; +static void SETUPDI_FreeInterfaceInstances(struct InterfaceInstances *instances) +{ + DWORD i; + + for (i = 0; i < instances->cInstances; i++) + { + struct InterfaceInfo *ifaceInfo = + (struct InterfaceInfo *)instances->instances[i].Reserved; + + HeapFree(GetProcessHeap(), 0, ifaceInfo->referenceString); + } + HeapFree(GetProcessHeap(), 0, instances->instances); +} + +/* Finds the interface with interface class InterfaceClassGuid in the device. + * Returns TRUE if found, and updates interfaceIndex to the index of the + * device's interfaces member where the given interface was found. + * Returns FALSE if not found. + */ +static BOOL SETUPDI_FindInterface(const struct DeviceInfo *devInfo, + const GUID *InterfaceClassGuid, DWORD *interfaceIndex) +{ + BOOL found = FALSE; + DWORD i; + + TRACE("%s\n", debugstr_guid(InterfaceClassGuid)); + + for (i = 0; !found && i < devInfo->cInterfaces; i++) + { + if (IsEqualGUID(&devInfo->interfaces[i].guid, InterfaceClassGuid)) + { + *interfaceIndex = i; + found = TRUE; + } + } + TRACE("returning %d (%d)\n", found, found ? *interfaceIndex : 0); + return found; +} + +/* Finds the interface instance with reference string ReferenceString in the + * interface instance map. Returns TRUE if found, and updates instanceIndex to + * the index of the interface instance's instances member + * where the given instance was found. Returns FALSE if not found. + */ +static BOOL SETUPDI_FindInterfaceInstance( + const struct InterfaceInstances *instances, + LPCWSTR ReferenceString, DWORD *instanceIndex) +{ + BOOL found = FALSE; + DWORD i; + + TRACE("%s\n", debugstr_w(ReferenceString)); + + for (i = 0; !found && i < instances->cInstances; i++) + { + SP_DEVICE_INTERFACE_DATA *ifaceData = &instances->instances[i]; + struct InterfaceInfo *ifaceInfo = + (struct InterfaceInfo *)ifaceData->Reserved; + + if (!ReferenceString && !ifaceInfo->referenceString) + { + *instanceIndex = i; + found = TRUE; + } + else if (ReferenceString && ifaceInfo->referenceString && + !lstrcmpiW(ifaceInfo->referenceString, ReferenceString)) + { + *instanceIndex = i; + found = TRUE; + } + } + TRACE("returning %d (%d)\n", found, found ? *instanceIndex : 0); + return found; +} + +/* Adds an interface with the given interface class and reference string to + * the device, if it doesn't already exist in the device. If iface is not + * NULL, returns a pointer to the newly added (or already existing) interface. + */ +static BOOL SETUPDI_AddInterfaceInstance(struct DeviceInfo *devInfo, + const GUID *InterfaceClassGuid, LPCWSTR ReferenceString, + SP_DEVICE_INTERFACE_DATA **ifaceData) +{ + BOOL newInterface = FALSE, ret; + DWORD interfaceIndex = 0; + struct InterfaceInstances *iface = NULL; + + TRACE("%p %s %s %p\n", devInfo, debugstr_guid(InterfaceClassGuid), + debugstr_w(ReferenceString), iface); + + if (!(ret = SETUPDI_FindInterface(devInfo, InterfaceClassGuid, + &interfaceIndex))) + { + if (!devInfo->cInterfacesAllocated) + { + devInfo->interfaces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(struct InterfaceInstances)); + if (devInfo->interfaces) + { + iface = &devInfo->interfaces[devInfo->cInterfacesAllocated++]; + newInterface = TRUE; + } + } + else if (devInfo->cInterfaces == devInfo->cInterfacesAllocated) + { + devInfo->interfaces = HeapReAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, devInfo->interfaces, + (devInfo->cInterfacesAllocated + 1) * + sizeof(struct InterfaceInstances)); + if (devInfo->interfaces) + { + iface = &devInfo->interfaces[devInfo->cInterfacesAllocated++]; + newInterface = TRUE; + } + } + else + iface = &devInfo->interfaces[devInfo->cInterfaces]; + } + else + iface = &devInfo->interfaces[interfaceIndex]; + if (iface) + { + DWORD instanceIndex = 0; + + if (!(ret = SETUPDI_FindInterfaceInstance(iface, ReferenceString, + &instanceIndex))) + { + SP_DEVICE_INTERFACE_DATA *instance = NULL; + + if (!iface->cInstancesAllocated) + { + iface->instances = HeapAlloc(GetProcessHeap(), 0, + sizeof(SP_DEVICE_INTERFACE_DATA)); + if (iface->instances) + instance = &iface->instances[iface->cInstancesAllocated++]; + } + else if (iface->cInstances == iface->cInstancesAllocated) + { + iface->instances = HeapReAlloc(GetProcessHeap(), 0, + iface->instances, + (iface->cInstancesAllocated + 1) * + sizeof(SP_DEVICE_INTERFACE_DATA)); + if (iface->instances) + instance = &iface->instances[iface->cInstancesAllocated++]; + } + else + instance = &iface->instances[iface->cInstances]; + if (instance) + { + struct InterfaceInfo *ifaceInfo = HeapAlloc(GetProcessHeap(), + 0, sizeof(struct InterfaceInfo)); + + if (ifaceInfo) + { + ret = TRUE; + if (ReferenceString) + { + ifaceInfo->referenceString = + HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(ReferenceString) + 1) * + sizeof(WCHAR)); + if (ifaceInfo->referenceString) + lstrcpyW(ifaceInfo->referenceString, + ReferenceString); + else + ret = FALSE; + } + else + ifaceInfo->referenceString = NULL; + if (ret) + { + iface->cInstances++; + instance->cbSize = + sizeof(SP_DEVICE_INTERFACE_DATA); + memcpy(&instance->InterfaceClassGuid, + InterfaceClassGuid, sizeof(GUID)); + instance->Flags = SPINT_ACTIVE; /* FIXME */ + instance->Reserved = (ULONG_PTR)ifaceInfo; + if (newInterface) + { + memcpy(&iface->guid, InterfaceClassGuid, + sizeof(GUID)); + devInfo->cInterfaces++; + } + /* FIXME: now create this homeboy in the registry */ + if (ifaceData) + *ifaceData = instance; + } + else + HeapFree(GetProcessHeap(), 0, ifaceInfo); + } + } + } + else + { + if (ifaceData) + *ifaceData = + &devInfo->interfaces[interfaceIndex].instances[instanceIndex]; + } + } + else + ret = FALSE; + TRACE("returning %d\n", ret); + return ret; +} + static struct DeviceInfo *SETUPDI_AllocateDeviceInfo(LPCWSTR instanceId, BOOL phantom) { @@ -137,6 +363,8 @@ static struct DeviceInfo *SETUPDI_Alloca (LPBYTE)&phantom, sizeof(phantom)); RegCloseKey(enumKey); } + devInfo->cInterfaces = devInfo->cInterfacesAllocated = 0; + devInfo->interfaces = NULL; } else { @@ -149,6 +377,8 @@ static struct DeviceInfo *SETUPDI_Alloca static void SETUPDI_FreeDeviceInfo(struct DeviceInfo *devInfo) { + DWORD i; + if (devInfo->key != INVALID_HANDLE_VALUE) RegCloseKey(devInfo->key); if (devInfo->phantom) @@ -165,6 +395,9 @@ static void SETUPDI_FreeDeviceInfo(struc } } HeapFree(GetProcessHeap(), 0, devInfo->instanceId); + for (i = 0; i < devInfo->cInterfaces; i++) + SETUPDI_FreeInterfaceInstances(&devInfo->interfaces[i]); + HeapFree(GetProcessHeap(), 0, devInfo->interfaces); HeapFree(GetProcessHeap(), 0, devInfo); } @@ -1803,6 +2036,8 @@ BOOL WINAPI SetupDiCreateDeviceInterface { struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet; struct DeviceInfo *devInfo; + SP_DEVICE_INTERFACE_DATA *iface = NULL; + BOOL ret; TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData, debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString), @@ -1830,9 +2065,21 @@ BOOL WINAPI SetupDiCreateDeviceInterface return FALSE; } devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved; - - FIXME("stub\n"); - return FALSE; + if ((ret = SETUPDI_AddInterfaceInstance(devInfo, InterfaceClassGuid, + ReferenceString, &iface))) + { + if (DeviceInterfaceData) + { + if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA)) + { + SetLastError(ERROR_INVALID_USER_BUFFER); + ret = FALSE; + } + else + memcpy(DeviceInterfaceData, iface, sizeof(*iface)); + } + } + return ret; } /*********************************************************************** diff --git a/dlls/setupapi/tests/devinst.c b/dlls/setupapi/tests/devinst.c index 8bf3a25..54a4b77 100644 --- a/dlls/setupapi/tests/devinst.c +++ b/dlls/setupapi/tests/devinst.c @@ -385,16 +385,13 @@ static void testCreateDeviceInterface(vo "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError()); ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0, NULL); - todo_wine ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError()); /* Creating the same interface a second time succeeds */ ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0, NULL); - todo_wine ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError()); ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, "Oogah", 0, NULL); - todo_wine ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError()); ret = pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, 0, &interfaceData); -- 1.4.1