WMI Abfragen sehr langsam

  • VB.NET

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von FormFollowsFunction.

    WMI Abfragen sehr langsam

    Moin moin

    Ich habe mir hier eine WMI Abfrage gemacht, um verschiedene Laufwerke zu ermitteln. Erstmal alles auf dem Form, später will ich das in eine Class setzen.
    Nun zu meinem Problem.

    Wenn ich das Prog. starte, dauert es viel länger die LW mit ListUSBDrive als mit ListDrive zu ermitteln.

    1.) Warum ist das so?
    2.) Kann ich die Abfrage kürzen? Weniger For/Each Schleifen?
    Das habe ich schon versucht, klappte aber nicht.

    Spoiler anzeigen

    Versuch zu Punkt 2.
    Ein Ausnahmefehler des Typs "System.Management.ManagementException" ist in System.Management.dll aufgetreten. Zusätzliche Informationen: Die Anfrage ist ungültig.

    VB.NET-Quellcode

    1. Private Sub ListUSBDrives()
    2. cmbDrives.Items.Clear()
    3. Dim query As String = "SELECT LD.DeviceID FROM Win32_DiskDrive DD " &
    4. "JOIN Win32_DiskDriveToDiskPartition DP ON DD.DeviceID=DP.Antecedent " &
    5. "JOIN Win32_LogicalDiskToPartition LP ON DP.Dependent=LP.Dependent " &
    6. "JOIN Win32_LogicalDisk LD ON LP.Dependent=LD.DeviceID " &
    7. "WHERE (DD.MediaType='External hard disk media' OR DD.MediaType='Removable media')"
    8. Dim searcher As New ManagementObjectSearcher(query)
    9. For Each logicalDisk As ManagementObject In searcher.Get()
    10. cmbDrives.Items.Add(logicalDisk("DeviceID").ToString())
    11. Next
    12. End Sub



    3.) Kann ich diese Abfragen bzgl. der "internen" und "externen" Laufwerke evtl noch anders gestallten? Die "DriveInfo" aus dem .Net filtert leider die USB-Festplatten zu "internen Festplatten" :(

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub ListDrives()
    2. If Not isCleaning Then
    3. cmbDrives.Items.Clear()
    4. For Each drive As DriveInfo In allDrives
    5. If drive.IsReady Then
    6. Dim label As String = drive.VolumeLabel
    7. If Not String.IsNullOrEmpty(label) AndAlso label.All(Function(c) Char.IsLetterOrDigit(c) OrElse Char.IsWhiteSpace(c)) Then
    8. cmbDrives.Items.Add(drive.Name) ' & " (" & label & ")")
    9. Else
    10. cmbDrives.Items.Add(drive.Name)
    11. End If
    12. End If
    13. Next
    14. If cmbDrives.Items.Count > 0 Then
    15. cmbDrives.SelectedIndex = 0
    16. End If
    17. End If
    18. End Sub
    19. Private Sub ListUSBDrives()
    20. If Not isCleaning Then
    21. cmbDrives.Items.Clear()
    22. ' Suchabfrage nur für USB- und Wechselmedienlaufwerke
    23. Dim searcher As New ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive WHERE (MediaType='External hard disk media' OR MediaType='Removable media')")
    24. For Each drive As ManagementObject In searcher.Get()
    25. Dim partitionsQuery As String = $"ASSOCIATORS OF {{Win32_DiskDrive.DeviceID='{drive("DeviceID")}'}} WHERE AssocClass = Win32_DiskDriveToDiskPartition"
    26. Dim partitionSearcher As New ManagementObjectSearcher(partitionsQuery)
    27. For Each partition As ManagementObject In partitionSearcher.Get()
    28. Dim logicalDisksQuery As String = $"ASSOCIATORS OF {{Win32_DiskPartition.DeviceID='{partition("DeviceID")}'}} WHERE AssocClass = Win32_LogicalDiskToPartition"
    29. Dim logicalDisksSearcher As New ManagementObjectSearcher(logicalDisksQuery)
    30. For Each logicalDisk As ManagementObject In logicalDisksSearcher.Get()
    31. cmbDrives.Items.Add(logicalDisk("DeviceID").ToString())
    32. Next
    33. Next
    34. Next
    35. If cmbDrives.Items.Count > 0 Then
    36. cmbDrives.SelectedIndex = 0
    37. End If
    38. End If
    39. End Sub
    40. Private Sub chkOnlyUSB_CheckedChanged(sender As Object, e As EventArgs) Handles chkOnlyUSB.CheckedChanged
    41. If Not chkOnlyUSB.Checked Then
    42. ListDrives()
    43. Else
    44. ListUSBDrives()
    45. End If
    46. End Sub



    Verschoben. ~Thunderbolt
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Thunderbolt“ ()

    Ich kenn mich mit WMI nicht aus aber Microsoft schreibt folgendes.

    MSDN schrieb:


    So verbessern Sie die Enumerationsleistung

    Legen Sie den Parameter lFlags fest, um die
    halbsynchrone Rückgabe der Daten mit einem Enumerator zu ermöglichen,
    der jedes Element aus WMI verwirft, während es übermittelt wird. Weitere
    Informationen finden Sie unter Aufrufen einer Methode.

    Verbessern der Enumerationsleistung

    Das bringt einen dann zu EnumerationOptions Klasse genauer gesagt zu der Eigenschaft ReturnImmediately mit Eigenschaft soll sich wohl die halbsynchrone Enumeration aktivieren lassen.
    Moin moin

    Vorweg zur Erklärung:
    Laufwerk " A:\ & B:\ " sind zwei M.2 SSD, welche mit jeweils einem identischem PCIe Adapter eingebunden sind. Alle anderen internen Laufwerke sind normale SSDs und eine HDD ( LW X:\ )

    Habe das ganze nun einmal in eine Class gebracht.
    Das Anzeigen der verschiedenen MediaTypen klappt, ist zwar noch immer etwas langsam beim ersten Starten und wenn ich von nur USB zu Internal umschalte, aber das geht wohl nicht schneller. :?:

    Das Problem:
    Wenn ich die Sortierung und die Filterung nach Duplikaten aus dem Code raus nehme ist die Liste durcheinander und LW A:\ wird doppelt ausgegeben. Siehe Bildanhang. ?(

    Spoiler anzeigen

    Die Class:

    VB.NET-Quellcode

    1. Public Class DriveManager
    2. Public Event DrivesListed As EventHandler(Of List(Of String))
    3. Friend onlyUSB As Boolean
    4. Public Enum MediaType
    5. ExternalOrRemovable = 1
    6. Fixed = 2
    7. End Enum
    8. Private Const ExternalOrRemovableQuery As String = "SELECT DeviceID FROM Win32_DiskDrive WHERE MediaType='External hard disk media' OR MediaType='Removable media'"
    9. Private Const FixedQuery As String = "SELECT DeviceID FROM Win32_DiskDrive WHERE MediaType='Fixed hard disk media'"
    10. Public Sub ListDrives(driveType As MediaType)
    11. Dim drivesList As New List(Of String)()
    12. Dim query As String = GetQueryByType(driveType)
    13. If query <> "" Then
    14. Dim searcher As New ManagementObjectSearcher(query)
    15. For Each drive As ManagementObject In searcher.Get()
    16. Dim partitionsQuery As String = $"ASSOCIATORS OF {{Win32_DiskDrive.DeviceID='{drive("DeviceID")}'}} WHERE AssocClass = Win32_DiskDriveToDiskPartition"
    17. Dim partitionSearcher As New ManagementObjectSearcher(partitionsQuery)
    18. For Each partition As ManagementObject In partitionSearcher.Get()
    19. Dim logicalDisksQuery As String = $"ASSOCIATORS OF {{Win32_DiskPartition.DeviceID='{partition("DeviceID")}'}} WHERE AssocClass = Win32_LogicalDiskToPartition"
    20. Dim logicalDisksSearcher As New ManagementObjectSearcher(logicalDisksQuery)
    21. For Each logicalDisk As ManagementObject In logicalDisksSearcher.Get()
    22. Dim driveID As String = logicalDisk("DeviceID").ToString() & "\"
    23. ' Prüfe auf Duplikate anhand einer anderen Eigenschaft
    24. If Not drivesList.Any(Function(d) d.StartsWith(driveID)) Then
    25. drivesList.Add(driveID)
    26. End If
    27. Next
    28. Next
    29. Next
    30. ' Sortiere die Liste der Laufwerksbuchstaben
    31. drivesList.Sort()
    32. RaiseEvent DrivesListed(Me, drivesList)
    33. End If
    34. End Sub
    35. Private Function GetQueryByType(driveType As MediaType) As String
    36. Select Case driveType
    37. Case MediaType.ExternalOrRemovable
    38. Return ExternalOrRemovableQuery
    39. Case MediaType.Fixed
    40. Return FixedQuery
    41. Case Else
    42. Return ""
    43. End Select
    44. End Function
    45. End Class


    Auf dem MainForm:

    VB.NET-Quellcode

    1. ' Aufruf in der Class
    2. Private Sub ListDrives()
    3. If driveManager.onlyUSB Then
    4. driveManager.ListDrives(CType(1, DriveManager.MediaType))
    5. Else
    6. driveManager.ListDrives(CType(2, DriveManager.MediaType))
    7. End If
    8. End Sub
    9. ' Event-Handler für das Event DrivesListed
    10. Private Sub driveManager_DrivesListed(sender As Object, drivesList As List(Of String)) Handles driveManager.DrivesListed
    11. cmbDrives.Items.Clear()
    12. For Each drive As String In drivesList
    13. cmbDrives.Items.Add(drive)
    14. Debug.WriteLine("Laufwerke: " & drive)
    15. Next
    16. If cmbDrives.Items.Count > 0 Then
    17. cmbDrives.SelectedIndex = 0
    18. End If
    19. End Sub
    20. ' Laufwerkerkennung basierend auf dem Zustand der Checkbox zu starten
    21. Private Sub chkOnlyUSB_CheckedChanged(sender As Object, e As EventArgs) Handles chkOnlyUSB.CheckedChanged
    22. driveManager.onlyUSB = chkOnlyUSB.Checked
    23. ListDrives()
    24. End Sub






    @Fakiz
    ​So verbessern Sie die Enumerationsleistung

    So ganz kapiere ich das nicht und das scheint wohl für Vb nicht zuzutreffen?
    Bilder
    • Laufwerke-1.jpg

      59,53 kB, 535×168, 81 mal angesehen
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Also um die Duplikate rauszubekommen kannst du auch vor drivesList.Sort() driveList.Distinct() aufrufen damit würdes du dann drivesList.Any(...) nicht mehr benötigen.
    Aber unterschied dürfte das wohl kaum machen.

    Zu den MS Empfehlungen. Die Optimierung von MS haben bei mir auch nur 30ms Auswirkung. Aber egal was ich mache, mit dem von dir gezeigten Code läuft das bei mir im schlimmsten Fall in 278ms durch.
    @-Franky-

    Nach meinen Recherchen, kann .Net mir das eben nicht so ausgeben. Z.B. mit:

    VB.NET-Quellcode

    1. Dim allDrives() As DriveInfo = DriveInfo.GetDrives()
    2. For Each drive As DriveInfo In allDrives
    3. cmbHdds.Items.Add(drive.Name)
    4. Next

    Das gibt mir "externe Festplatten" nicht separat aus sondern nur als Festplatte.
    Mit den API habe ich bis her noch nichts gemacht, soweit bin ich noch nicht.
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    @VB1963
    DriveType.Removable bzw. DriveType.Fixed sind leider wertlos,
    da manche über USB angeschlossene Festplatten als .Fixed erkannt werden.

    @Amelie
    Habe mal eine ähnliche, noch langsamere Methode :D rausgekramt, vieleicht bringts dir was:

    VB.NET-Quellcode

    1. Public Shared Function GetUSBDrives() As USBDriveInfo()
    2. Dim usbDriveInfos As New List(Of USBDriveInfo)
    3. Using Win32_PnPEntitySearcher As New ManagementObjectSearcher(
    4. "SELECT * FROM Win32_PnPEntity WHERE (DeviceID Like ""USBSTOR%"" OR DeviceID Like ""SCSI%"") AND PNPClass = ""DiskDrive""")
    5. For Each pnpEntityQueryObj As ManagementObject In Win32_PnPEntitySearcher.Get()
    6. Using Win32_DiskDriveSearcher As New ManagementObjectSearcher(
    7. "SELECT * FROM Win32_DiskDrive WHERE Not MediaType Like ""Fixed hard disk media""")
    8. For Each diskDriveQueryObj As ManagementObject In Win32_DiskDriveSearcher.Get()
    9. If Not pnpEntityQueryObj.GetPropertyValue("PNPDeviceID").Equals(diskDriveQueryObj.GetPropertyValue("PNPDeviceID")) Then
    10. For Each diskPartitionQueryObj As ManagementObject In diskDriveQueryObj.GetRelated("Win32_DiskPartition")
    11. For Each logicalDiskQueryObj As ManagementBaseObject In diskPartitionQueryObj.GetRelated("Win32_LogicalDisk")
    12. Dim usbDriveInfo As New USBDriveInfo(logicalDiskQueryObj.GetPropertyValue("Name").ToString)
    13. If Not usbDriveInfos.Exists(Function(_x) _x.Name = usbDriveInfo.Name) Then
    14. usbDriveInfos.Add(usbDriveInfo)
    15. End If
    16. Next
    17. Next
    18. End If
    19. Next
    20. End Using
    21. Next
    22. End Using
    23. Return usbDriveInfos.ToArray
    24. End Function

    Ziel war es, ausschließlich über USB angeschlossene Speichermedien zu erfassen,
    daher habe ich bei "SELECT * FROM Win32_PnPEntity WHERE (DeviceID Like ""USBSTOR%"" OR DeviceID Like ""SCSI%"") AND PNPClass = ""DiskDrive""" angesetzt.
    Wahrscheinlich eher suboptimal, ich habe es aber nicht anders hinbekommen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „FormFollowsFunction“ ()