- Implement SetupDiCreateDeviceInfoListExW
- Do according changes in SetupDiDestroyDeviceInfoList
- Implement SetupDiEnumDeviceInfo
- Don't open registry with full rights in SetupDiClassGuidsFromNameExW
- Set last error in SetupDiClassNameFromGuidExW in case of problem
- Do W->A conversion for InfSectionWithExt string in SetupDiGetActualSectionToInstallA

Following changes break serial port devices enumeration on Wine. I'll work on this problem later.
- Implement SetupDiGetClassDevsW
- Disable some code in SetupDiEnumDeviceInterfaces and SetupDiGetDeviceInterfaceDetailA

Now, you should be able to list devices classes, and enumerate devices related to each class
Modified: trunk/reactos/lib/setupapi/devinst.c

Modified: trunk/reactos/lib/setupapi/devinst.c
--- trunk/reactos/lib/setupapi/devinst.c	2005-07-05 01:18:07 UTC (rev 16422)
+++ trunk/reactos/lib/setupapi/devinst.c	2005-07-05 08:48:43 UTC (rev 16423)
@@ -68,6 +68,34 @@
                                   'C','o','n','t','r','o','l','\\',
                                   'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
 
+
+typedef struct _DeviceInfo
+{
+    LIST_ENTRY ItemEntry;
+#ifdef __WINE__
+    PWSTR InterfaceName; /* "COMx:" */
+    LPGUID InterfaceGuid; /* GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR */
+#else
+    WCHAR DeviceInstance[0];
+#endif
+} DeviceInfo;
+
+#define SETUP_DEV_INFO_LIST_MAGIC 0xd00ff056
+
+typedef struct _DeviceInfoList
+{
+    DWORD magic;
+    GUID ClassGuid;
+    HWND hWnd;
+    HKEY HKLM; /* Local or distant HKEY_LOCAL_MACHINE registry key */
+    DWORD numberOfEntries;
+    LIST_ENTRY ListHead;
+} DeviceInfoList;
+
+/* FIXME: header mess */
+DEFINE_GUID(GUID_NULL,
+  0x00000000L, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
 /***********************************************************************
  *              SetupDiBuildClassInfoList  (SETUPAPI.@)
  */
@@ -344,7 +372,7 @@
 	*RequiredSize = 0;
 
     hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
-                                            KEY_ALL_ACCESS,
+                                            KEY_ENUMERATE_SUB_KEYS,
                                             DIOCR_INSTALLER,
                                             MachineName,
                                             Reserved);
@@ -372,7 +400,7 @@
 	    if (RegOpenKeyExW(hClassesKey,
 			      szKeyName,
 			      0,
-			      KEY_ALL_ACCESS,
+			      KEY_QUERY_VALUE,
 			      &hClassKey))
 	    {
 		RegCloseKey(hClassesKey);
@@ -503,9 +531,10 @@
 {
     HKEY hKey;
     DWORD dwLength;
+    LONG rc;
 
     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
-                                     KEY_ALL_ACCESS,
+                                     KEY_QUERY_VALUE,
                                      DIOCR_INSTALLER,
                                      MachineName,
                                      Reserved);
@@ -517,13 +546,15 @@
     if (RequiredSize != NULL)
     {
 	dwLength = 0;
-	if (RegQueryValueExW(hKey,
+	rc = RegQueryValueExW(hKey,
 			     Class,
 			     NULL,
 			     NULL,
 			     NULL,
-			     &dwLength))
+			     &dwLength);
+	if (rc != ERROR_SUCCESS)
 	{
+	    SetLastError(rc);
 	    RegCloseKey(hKey);
 	    return FALSE;
 	}
@@ -532,13 +563,15 @@
     }
 
     dwLength = ClassNameSize * sizeof(WCHAR);
-    if (RegQueryValueExW(hKey,
+    rc = RegQueryValueExW(hKey,
 			 Class,
 			 NULL,
 			 NULL,
 			 (LPBYTE)ClassName,
-			 &dwLength))
+			 &dwLength);
+    if (rc != ERROR_SUCCESS)
     {
+	SetLastError(rc);
 	RegCloseKey(hKey);
 	return FALSE;
     }
@@ -597,26 +630,81 @@
 			       PCWSTR MachineName,
 			       PVOID Reserved)
 {
-  FIXME("\n");
-  return (HDEVINFO)INVALID_HANDLE_VALUE;
+  DeviceInfoList* list;
+
+  TRACE("%p %p %p %p\n", ClassGuid, hwndParent, MachineName, Reserved);
+
+  list = HeapAlloc(GetProcessHeap(), 0, sizeof(DeviceInfoList));
+  if (!list)
+    return (HDEVINFO)INVALID_HANDLE_VALUE;
+
+  list->magic = SETUP_DEV_INFO_LIST_MAGIC;
+  list->hWnd = hwndParent;
+  list->numberOfEntries = 0;
+  /* FIXME: open distant registry */
+  //if (RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM) != ERROR_SUCCESS)
+  if (RegOpenKey(HKEY_LOCAL_MACHINE, NULL, &list->HKLM) != ERROR_SUCCESS)
+  {
+    HeapFree(GetProcessHeap(), 0, list);
+    return (HDEVINFO)INVALID_HANDLE_VALUE;
+  }
+  memcpy(
+    &list->ClassGuid,
+    ClassGuid ? ClassGuid : &GUID_NULL,
+    sizeof(list->ClassGuid));
+  InitializeListHead(&list->ListHead);
+  return (HDEVINFO)list;
 }
 
 /***********************************************************************
  *		SetupDiEnumDeviceInfo (SETUPAPI.@)
  */
 BOOL WINAPI SetupDiEnumDeviceInfo(
-        HDEVINFO  devinfo,
-        DWORD  index,
-        PSP_DEVINFO_DATA info)
+        HDEVINFO DeviceInfoSet,
+        DWORD MemberIndex,
+        PSP_DEVINFO_DATA DeviceInfoData)
 {
-    FIXME("%p %ld %p\n", devinfo, index, info);
+    BOOL ret = FALSE;
 
-    if(info==NULL)
-        return FALSE;
-    if(info->cbSize < sizeof(*info))
-        return FALSE;
-
-    return FALSE;
+    TRACE("%p, 0x%08lx, %p\n", DeviceInfoSet, MemberIndex, DeviceInfoData);
+    if (!DeviceInfoData)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
+    {
+        DeviceInfoList *list = (DeviceInfoList *)DeviceInfoSet;
+        
+        if (list->magic != SETUP_DEV_INFO_LIST_MAGIC)
+            SetLastError(ERROR_INVALID_HANDLE);
+        else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
+            SetLastError(ERROR_INVALID_PARAMETER);
+        else if (MemberIndex >= list->numberOfEntries)
+            SetLastError(ERROR_NO_MORE_ITEMS);
+        else
+        {
+            PLIST_ENTRY ItemList = list->ListHead.Flink;
+            DeviceInfo* DevInfo;
+            while (MemberIndex-- > 0)
+                ItemList = ItemList->Flink;
+            DevInfo = (DeviceInfo *)ItemList;
+#ifdef __WINE__
+            memcpy(&DeviceInfoData->ClassGuid,
+                DevInfo->InterfaceGuid,
+                sizeof(GUID));
+            DeviceInfoData->DevInst = 0; /* FIXME */
+            DeviceInfoData->Reserved = 0;
+#else
+            memcpy(&DeviceInfoData->ClassGuid,
+                &list->ClassGuid, /* FIXME */
+                sizeof(GUID));
+            DeviceInfoData->DevInst = 0; /* FIXME */
+            DeviceInfoData->Reserved = 0;
+#endif
+            ret = TRUE;
+        }
+    }
+    else
+        SetLastError(ERROR_INVALID_HANDLE);
+    return ret;
 }
 
 /***********************************************************************
@@ -653,10 +741,12 @@
                                                 InfSectionWithExtSize, RequiredSize,
                                                 Extension ? &ExtensionW : NULL);
 
-    if (InfSectionWithExt)
+    if (bResult && InfSectionWithExt)
     {
+         bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
+             InfSectionWithExtSize, NULL, NULL) != 0;
     }
-    if (Extension)
+    if (bResult && Extension)
     {
         if (ExtensionW == NULL)
             *Extension = NULL;
@@ -880,20 +970,7 @@
     return ret;
 }
 
-#define SETUP_SERIAL_PORT_MAGIC 0xd00ff055
-
-typedef struct _SerialPortName
-{
-    WCHAR name[5];
-} SerialPortName;
-
-typedef struct _SerialPortList
-{
-    DWORD magic;
-    UINT  numPorts;
-    SerialPortName names[1];
-} SerialPortList;
-
+#ifdef __WINE__
 static HDEVINFO SETUP_CreateSerialDeviceList(void)
 {
     static const size_t initialSize = 100;
@@ -964,7 +1041,72 @@
     TRACE("returning %p\n", ret);
     return ret;
 }
+#endif /* __WINE__ */
 
+static HDEVINFO SETUP_CreateDevListFromClass(
+       PCWSTR MachineName,
+       LPGUID class)
+{
+    HDEVINFO hDeviceInfo;
+    HKEY KeyClass;
+    LONG rc;
+    DWORD subKeys = 0, maxSubKey;
+    DeviceInfo* deviceInfo;
+    DWORD i;
+
+    hDeviceInfo = SetupDiCreateDeviceInfoListExW(class, NULL, MachineName, NULL);
+    if (hDeviceInfo == INVALID_HANDLE_VALUE)
+        return INVALID_HANDLE_VALUE;
+
+    KeyClass = SetupDiOpenClassRegKeyExW(class, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, DIOCR_INSTALLER, MachineName, NULL);
+    if (KeyClass == INVALID_HANDLE_VALUE)
+    {
+        SetupDiDestroyDeviceInfoList(hDeviceInfo);
+        return INVALID_HANDLE_VALUE;
+    }
+
+    rc = RegQueryInfoKeyW(
+        KeyClass,
+        NULL, NULL,
+        NULL,
+        &subKeys,
+        &maxSubKey,
+        NULL, NULL, NULL, NULL, NULL, NULL);
+    if (rc != ERROR_SUCCESS)
+    {
+        RegCloseKey(KeyClass);
+        SetLastError(rc);
+        return INVALID_HANDLE_VALUE;
+    }
+
+    FIXME("subKeys %ld, maxSubKey %ld\n", subKeys, maxSubKey);
+    for (i = 0; i < subKeys; i++)
+    {
+        deviceInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DeviceInfo) + maxSubKey * sizeof(WCHAR));
+        if (!deviceInfo)
+        {
+           SetupDiDestroyDeviceInfoList(hDeviceInfo);
+           SetLastError(ERROR_NO_SYSTEM_RESOURCES);
+           return INVALID_HANDLE_VALUE;
+        }
+        rc = RegEnumKeyW(KeyClass, i, &deviceInfo->DeviceInstance[0], maxSubKey);
+        if (rc == ERROR_NO_MORE_ITEMS)
+            break;
+        if (rc != ERROR_SUCCESS)
+        {
+           SetupDiDestroyDeviceInfoList(hDeviceInfo);
+           SetLastError(rc);
+           return INVALID_HANDLE_VALUE;
+        }
+        InsertTailList(&((DeviceInfoList*)hDeviceInfo)->ListHead, &deviceInfo->ItemEntry);
+        ((DeviceInfoList*)hDeviceInfo)->numberOfEntries++;
+    }
+
+    RegCloseKey(KeyClass);
+
+    return hDeviceInfo;
+}
+
 /***********************************************************************
  *		SetupDiGetClassDevsW (SETUPAPI.@)
  */
@@ -979,19 +1121,29 @@
     TRACE("%s %s %p 0x%08lx\n", debugstr_guid(class), debugstr_w(enumstr),
      parent, flags);
 
+    if (flags & DIGCF_PRESENT)
+        FIXME(": flag DIGCF_PRESENT ignored\n");
+    if (flags & DIGCF_PROFILE)
+        FIXME(": flag DIGCF_PROFILE ignored\n");
+
     if (enumstr)
         FIXME(": unimplemented for enumerator strings (%s)\n",
          debugstr_w(enumstr));
     else if (flags & DIGCF_ALLCLASSES)
         FIXME(": unimplemented for DIGCF_ALLCLASSES\n");
+    else if (flags & DIGCF_DEVICEINTERFACE)
+        FIXME(": unimplemented for DIGCF_DEVICEINTERFACE\n");
     else
     {
-        if (IsEqualIID(class, &GUID_DEVINTERFACE_COMPORT))
+#ifdef __WINE__
+        if (IsEqualIID(class, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR))
             ret = SETUP_CreateSerialDeviceList();
-        else if (IsEqualIID(class, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR))
-            ret = SETUP_CreateSerialDeviceList();
         else
-            FIXME("(%s): stub\n", debugstr_guid(class));
+#else
+        {
+            ret = SETUP_CreateDevListFromClass(NULL, (LPGUID)class);
+        }
+#endif
     }
     return ret;
 }
@@ -1016,20 +1168,27 @@
         FIXME(": unimplemented with PSP_DEVINFO_DATA set\n");
     else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
     {
-        /* FIXME: this assumes the only possible enumeration is of serial
-         * ports.
-         */
-        SerialPortList *list = (SerialPortList *)DeviceInfoSet;
+        DeviceInfoList *list = (DeviceInfoList *)DeviceInfoSet;
 
-        if (list->magic == SETUP_SERIAL_PORT_MAGIC)
+        if (list->magic == SETUP_DEV_INFO_LIST_MAGIC)
         {
-            if (MemberIndex >= list->numPorts)
+            if (MemberIndex >= list->numberOfEntries)
                 SetLastError(ERROR_NO_MORE_ITEMS);
             else
             {
+                PLIST_ENTRY ItemList = list->ListHead.Flink;
+                DeviceInfo* DevInfo;
+                while (MemberIndex-- > 0)
+                    ItemList = ItemList->Flink;
+                DevInfo = (DeviceInfo *)ItemList;
+
                 DeviceInterfaceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+#ifdef __WINE__
+                /* FIXME: this assumes the only possible enumeration is of serial
+                 * ports.
+                 */
                 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
-                 &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR,
+                 DevInfo->InterfaceGuid,
                  sizeof(DeviceInterfaceData->InterfaceClassGuid));
                 DeviceInterfaceData->Flags = 0;
                 /* Note: this appears to be dangerous, passing a private
@@ -1037,8 +1196,10 @@
                  * expected lifetime of the device data is the same as the
                  * HDEVINFO; once that is closed, the data are no longer valid.
                  */
-                DeviceInterfaceData->Reserved =
-                 (ULONG_PTR)&list->names[MemberIndex].name;
+                DeviceInterfaceData->Reserved = (ULONG_PTR)DevInfo->InterfaceName;
+#else
+                FIXME("implemented\n");
+#endif
                 ret = TRUE;
             }
         }
@@ -1060,13 +1221,17 @@
     TRACE("%p\n", devinfo);
     if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
     {
-        /* FIXME: this assumes the only possible enumeration is of serial
-         * ports.
-         */
-        SerialPortList *list = (SerialPortList *)devinfo;
+        DeviceInfoList *list = (DeviceInfoList *)devinfo;
 
-        if (list->magic == SETUP_SERIAL_PORT_MAGIC)
+        if (list->magic == SETUP_DEV_INFO_LIST_MAGIC)
         {
+            PLIST_ENTRY ListEntry;
+            while (!IsListEmpty(&list->ListHead))
+            {
+                ListEntry = RemoveHeadList(&list->ListHead);
+                HeapFree(GetProcessHeap(), 0, ListEntry);
+            }
+            RegCloseKey(list->HKLM);
             HeapFree(GetProcessHeap(), 0, list);
             ret = TRUE;
         }
@@ -1101,13 +1266,14 @@
         SetLastError(ERROR_INVALID_PARAMETER);
     else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
     {
-        /* FIXME: this assumes the only possible enumeration is of serial
-         * ports.
-         */
-        SerialPortList *list = (SerialPortList *)DeviceInfoSet;
+        DeviceInfoList *list = (DeviceInfoList *)DeviceInfoSet;
 
-        if (list->magic == SETUP_SERIAL_PORT_MAGIC)
+        if (list->magic == SETUP_DEV_INFO_LIST_MAGIC)
         {
+#ifdef __WINE__
+            /* FIXME: this assumes the only possible enumeration is of serial
+             * ports.
+             */
             LPCWSTR devName = (LPCWSTR)DeviceInterfaceData->Reserved;
             DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A) +
              lstrlenW(devName);
@@ -1142,6 +1308,10 @@
                 }
                 ret = TRUE;
             }
+#else /* __WINE__ */
+            FIXME("unimplemented\n");
+            ret = FALSE;
+#endif /* __WINE__ */
         }
         else
             SetLastError(ERROR_INVALID_HANDLE);