DiskPart DiskNummer und VolumenNummer

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 35 Antworten in diesem Thema. Der letzte Beitrag () ist von Amelie.

    Aber zurück zum Thema. Probiere dich mal mit den APIs aus. Am Ende wirst Du feststellen, das das gar nicht so kompliziert ist.

    1. API CreateFile -> Handle auf das Laufwerk
    2. API DeviceIoControl(Handle, IOCTL_STORAGE_GET_DEVICE_NUMBER, ...) -> Struct STORAGE_DEVICE_NUMBER
    3. API CloseHandle <- Handle vom Laufwerk

    Wichtig ist hier CreateFile mit den richtigen Flags aufzurufen und noch wichtiger ist es das Handle mit CloseHandle wieder frei zugeben.

    Allein mit CreateFile und CloseHandle kann man (und das war in dem Fall beabsichtigt) mal eben den Zugriff auf ein CD-Rom Laufwerk bzw. auf die eingelegte CD unterbinden/sperren.
    Mfg -Franky-
    Da bin ich wohl mal wieder das Küken in der Runde, mit meinen geschmeidigen (noch) 26. ;)
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)
    @siycah @-Franky-

    Ich habe nun das umgebaut.

    stackoverflow.com/questions/55…-device-from-the-drive-le

    Bei vergleichen mit Diskpart ==> List Disk stimmen die Datenträger Nummern überein.

    VB.NET-Quellcode

    1. Public Function GetDiskNumberByDriveLetter(ByVal driveLetter As Char) As Integer
    2. Dim diskNumberFound As Integer = -1 ' Standardwert für den Fall, dass das Laufwerk nicht gefunden wird
    3. Dim searcher As New ManagementObjectSearcher("SELECT DeviceID FROM Win32_LogicalDisk")
    4. For Each queryObj As ManagementObject In searcher.Get()
    5. Dim devID As String = TryCast(queryObj("DeviceID"), String)
    6. If devID IsNot Nothing AndAlso devID(0) = driveLetter Then
    7. Dim partitions As ManagementObjectCollection = queryObj.GetRelated("Win32_DiskPartition")
    8. For Each partition As ManagementObject In partitions
    9. Dim disks As ManagementObjectCollection = partition.GetRelated("Win32_DiskDrive")
    10. For Each disk As ManagementObject In disks
    11. diskNumberFound = Convert.ToInt32(disk("Index"))
    12. Exit For ' Verlasse die innere Schleife, nachdem ein Wert gefunden wurde
    13. Next
    14. Exit For ' Verlasse die äußere Schleife, nachdem ein Wert gefunden wurde
    15. Next
    16. Exit For ' Verlasse die äußerste Schleife, nachdem ein Wert gefunden wurde
    17. End If
    18. Next
    19. Debug.WriteLine($"Für Disk:({driveLetter}) wurde folgende DiskNr:({diskNumberFound}) ermittelt.")
    20. Return diskNumberFound ' Gib den gefundenen Wert zurück
    21. End Function
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Dein Code ist sehr viel komplizierter, als er sein müsste.

    Wenn du sowieso nur den ersten Wert haben willst, dann spar dir die Schleifen und rufe direkt Index 0 auf.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)
    @siycah

    OK
    Ist so denke ich besser und Resourcen schonender? Oder geht es noch einfacher :?:
    Weil ich weiß ja immer den "driveLetter" und brauche dazu nur die richtige "Datenträgernummer".

    VB.NET-Quellcode

    1. Public Function GetDiskNumberByDriveLetter(ByVal driveLetter As Char) As Integer
    2. Dim diskNumberFound As Integer = -1 ' Standardwert für den Fall, dass das Laufwerk nicht gefunden wird
    3. Dim searcher As New ManagementObjectSearcher("SELECT DeviceID FROM Win32_LogicalDisk WHERE DeviceID LIKE '" & driveLetter & ":%'")
    4. Dim queryObj As ManagementObject = searcher.Get().Cast(Of ManagementObject)().FirstOrDefault()
    5. If queryObj IsNot Nothing Then
    6. Dim partitions As ManagementObjectCollection = queryObj.GetRelated("Win32_DiskPartition")
    7. Dim partition As ManagementObject = partitions.Cast(Of ManagementObject)().FirstOrDefault()
    8. If partition IsNot Nothing Then
    9. Dim disks As ManagementObjectCollection = partition.GetRelated("Win32_DiskDrive")
    10. Dim disk As ManagementObject = disks.Cast(Of ManagementObject)().FirstOrDefault()
    11. If disk IsNot Nothing Then
    12. diskNumberFound = Convert.ToInt32(disk("Index"))
    13. End If
    14. End If
    15. End If
    16. Debug.WriteLine($"Für Disk:({driveLetter}:) wurde folgende DiskNr:({diskNumberFound}) ermittelt.")
    17. Return diskNumberFound ' Gib den gefundenen Wert zurück
    18. End Function
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Du verschachtelst deinen Code zu sehr.

    Wenn die Bedingung nicht zutrifft, dann kannst du besser die Schleife/Methode/was auch immer abbrechen oder fortführen.

    VB.NET-Quellcode

    1. if partition is nothing then return -1 ' du musst dann nichts weiter machen. Brich' ab und lass den Aufrufer den Fehlerfall behandeln.
    2. ' ...
    3. if disk is nothing then return -1 ' hier genau so


    Alternativ schmeißt du eine Exception:

    VB.NET-Quellcode

    1. if partition is nothing then throw new Exception("Invalid partition!") ' oder so
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)
    @siycah

    OK so in etwar :?:

    VB.NET-Quellcode

    1. Public Function GetDiskNumberByDriveLetter(ByVal driveLetter As Char) As Integer
    2. Dim diskNumberFound As Integer = -1 ' Standardwert für den Fall, dass das Laufwerk nicht gefunden wird.
    3. Dim searcher As New ManagementObjectSearcher("SELECT DeviceID FROM Win32_LogicalDisk WHERE DeviceID LIKE '" & driveLetter & ":%'")
    4. Dim queryObj As ManagementObject = searcher.Get().Cast(Of ManagementObject)().FirstOrDefault()
    5. If queryObj Is Nothing Then Return -1 ' Wenn das Laufwerk nicht gefunden wurde.
    6. Dim partitions As ManagementObjectCollection = queryObj.GetRelated("Win32_DiskPartition")
    7. Dim partition As ManagementObject = partitions.Cast(Of ManagementObject)().FirstOrDefault()
    8. If partition Is Nothing Then Return -1 ' Wenn die Partition nicht gefunden wurde.
    9. Dim disks As ManagementObjectCollection = partition.GetRelated("Win32_DiskDrive")
    10. Dim disk As ManagementObject = disks.Cast(Of ManagementObject)().FirstOrDefault()
    11. If disk IsNot Nothing Then
    12. diskNumberFound = Convert.ToInt32(disk("Index"))
    13. End If
    14. Debug.WriteLine($"Für Disk:({driveLetter}:) wurde folgende DiskNr:({diskNumberFound}) ermittelt.")
    15. Return diskNumberFound ' Gibt den gefundenen Wert zurück
    16. End Function
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Ja, das sieht doch ganz vernünftig aus. Gut, die expliziten Typangaben sind eigentlich optional und aus dem If-Block in Zeile#16 lässt sich ein Einzeiler machen, aber sonst passt es.
    Stellt sich nur die Frage, ob Du mit der -1 was anfangen kannst, wenn sie kommt, da Du dann nicht weißt, an welcher Stelle der Abbruch kam. Ob da Exceptions zuviel sind, musst Du selber wissen. Notfalls ließe sich aber ein aussagekräftigerer Return-Value in Form eines Enums hernehmen. Aber das musst Du selber wissen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @Amelie Jo, das sieht schon gut lesbar aus.

    Weiter vereinfachen kann man es, wie @VaporiZed sagt, wenn man die expliziten Typangaben weglässt.
    Du hast den ganzen Compiler installiert, dann nutz auch den ganzen Compiler ;)

    VB.NET-Quellcode

    1. Public Function GetDiskNumberByDriveLetter(ByVal driveLetter As Char) As Integer
    2. Dim diskNumberFound = -1 ' Standardwert für den Fall, dass das Laufwerk nicht gefunden wird.
    3. Dim searcher As New ManagementObjectSearcher("SELECT DeviceID FROM Win32_LogicalDisk WHERE DeviceID LIKE '" & driveLetter & ":%'")
    4. Dim queryObj = searcher.Get().Cast(Of ManagementObject)().FirstOrDefault()
    5. If queryObj Is Nothing Then Return -1 ' Wenn das Laufwerk nicht gefunden wurde.
    6. Dim partitions = queryObj.GetRelated("Win32_DiskPartition")
    7. Dim partition = partitions.Cast(Of ManagementObject)().FirstOrDefault()
    8. If partition Is Nothing Then Return -1 ' Wenn die Partition nicht gefunden wurde.
    9. Dim disks = partition.GetRelated("Win32_DiskDrive")
    10. Dim disk = disks.Cast(Of ManagementObject)().FirstOrDefault()
    11. If disk IsNot Nothing Then diskNumberFound = Convert.ToInt32(disk("Index"))
    12. Debug.WriteLine($"Für Disk:({driveLetter}:) wurde folgende DiskNr:({diskNumberFound}) ermittelt.")
    13. Return diskNumberFound ' Gibt den gefundenen Wert zurück
    14. End Function


    Was ich bei deinen Strings noch ändern würde, ist mehr Interpolated Strings verwenden.

    Konkret:
    "SELECT DeviceID FROM Win32_LogicalDisk WHERE DeviceID LIKE '" & driveLetter & ":%'"

    Lass das Konkatinieren; ist nur unnötige Speicherverschwendung. Roslyn kann folgendes viel besser optimieren: $"SELECT DeviceID FROM Win32_LogicalDisk WHERE DeviceID LIKE '{driveLetter}:%'"
    Ist außerdem viel lesbarer.

    @VaporiZed
    Üblicherweise wird -1 als Wert genommen, der keinen anderen Wert darstellt, also ein ungültiges Ergebnis.
    99% aller C-Funktionen arbeiten ähnlich; ich finde den Ansatz persönlich auch nicht falsch.

    Beispiel hier: man7.org/linux/man-pages/man2/socket.2.html


    RETURN VALUE
    On success, a file descriptor for the new socket is returned. On
    error, -1 is returned, and errno is set to indicate the error.


    In dem konkreten Fall, eine positive Zahl ist der Filedescriptor. 0, 1, 2 sind reserviert (stdin, stdout, stderr) und alle darüber sind andere Dateien (ähnlich wie das Windows HANDLE).
    Eine negative Zahl (zumeist -1) zeigt auf, dass ein Fehler passiert ist und dann wird entsprechend errno gesetzt.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)
    @siycah @VaporiZed

    Ich muss mich noch an die Schreibweise gewöhnen: {driveLetter} .. hatte bis vor kurzem noch VS 2013 das konnte nur die alte....

    Nach ein paar Tests mit "ungültigen / gültigen" DriveLetter scheint das so zu funktionieren. Gültige prüfte ich mit DiskPart nach. :!:

    VB.NET-Quellcode

    1. Public Enum DiskStatus
    2. DriveNotFound
    3. PartitionNotFound
    4. DiskNotFound
    5. Success
    6. End Enum
    7. Public Function GetDiskNumberByDriveLetter(ByVal driveLetter As Char) As DiskStatus
    8. Dim diskNumberFound As Integer = -1 ' Standardwert für den Fall, dass das Laufwerk nicht gefunden wird.
    9. Dim searcher As New ManagementObjectSearcher("SELECT DeviceID FROM Win32_LogicalDisk WHERE DeviceID LIKE '{driveLetter}:%'")
    10. Dim queryObj As ManagementObject = searcher.Get().Cast(Of ManagementObject)().FirstOrDefault()
    11. If queryObj Is Nothing Then Return DiskStatus.DriveNotFound ' Wenn das Laufwerk nicht gefunden wurde.
    12. Dim partitions As ManagementObjectCollection = queryObj.GetRelated("Win32_DiskPartition")
    13. Dim partition As ManagementObject = partitions.Cast(Of ManagementObject)().FirstOrDefault()
    14. If partition Is Nothing Then Return DiskStatus.PartitionNotFound ' Wenn die Partition nicht gefunden wurde.
    15. Dim disks As ManagementObjectCollection = partition.GetRelated("Win32_DiskDrive")
    16. Dim disk As ManagementObject = disks.Cast(Of ManagementObject)().FirstOrDefault()
    17. If disk IsNot Nothing Then diskNumber = Convert.ToInt32(disk("Index"))
    18. Debug.WriteLine($"Für Disk:({driveLetter}:) wurde folgende DiskNr:({diskNumber}) ermittelt.")
    19. Return DiskStatus.Success ' Erfolgreiche Rückgabe, wenn das Laufwerk und die Partition gefunden wurden.
    20. End Function
    21. ' MessageBox nur bei Fehler anzeigen
    22. Public Sub ShowDiskStatus(driveletter As Char)
    23. Dim result As DiskStatus = GetDiskNumberByDriveLetter(driveletter)
    24. If result <> DiskStatus.Success Then
    25. MessageBox.Show($"Result: {result.ToString()}", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information)
    26. End If
    27. End Sub




    EDIT: 08:25 Uhr
    Habe nun meinen Logger dazu genommen.

    VB.NET-Quellcode

    1. Public Sub ShowDiskStatus(driveletter As Char)
    2. Dim result As DiskStatus = GetDiskNumberByDriveLetter(driveletter)
    3. If result <> DiskStatus.Success Then
    4. eventlogger.EntryToFile(EntryType.Failure, $"Mitteilung: {result.ToString()}")
    5. End If
    6. End Sub
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:

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

    Nach Möglichkeit solltest du immer versuchen, auf dem neuesten Stand zu sein.

    Gilt sowohl für Entwicklertools, als auch für das Betriebssystem.

    String-Interpolation kam bereits 2015 raus und würde nun fast in die dritte Klasse gehen ;)
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)
    Warum denn nicht gleich die neueste Version, 2022?
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)
    Dann wird es höchste Zeit, das Betriebssystem zu wechseln. Windows 7 erhält seit einigen Jahren keine Sicherheitsupdates mehr und ist als Risiko zu behandeln.

    Upgraden geht schnell und einfach. Wenn einem die neue Shell nicht gefällt, kann man das mit Classic Shell immer noch ändern
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)
    Ich habe das öfter auf meinem PC mit Windows 10 probiert. Das ist sooooo unerträglich lahm..
    Ja und ganz ehrlich, ich hatte bisher noch nie einen Virus etc auf meinem Win 7 PC.
    Ich habe da dieses riesige Paket fast 4-GB groß mit Patches Updates usw.. drauf..

    Ich denke für mich reicht das VS 2017 erstmal aus, merke schon jetzt das es wesentlich mehr den PC belastet als VS2015.
    Bilder
    • Unbenannt-1.jpg

      131,26 kB, 500×318, 26 mal angesehen
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh: