Ich verwende aus dem VS2008 deutsch Sprache BASIC.
Mit Hilfe von WMI und Registry ist es mir gelungen die VID und PID der
angeschlossenen USB-Festplatten zu ermitteln.
Aber nun klemmt es gewaltig.
Zum ersten habe ich entdeckt, daß die HID.DLL diese Möglichkeiten auch
anbietet und ich überlege, diese auch zu nutzen. Aber über
HidD_GetHidGuid(guid) bin ich nicht hinausgekommen.
Zum zweiten suche ich darin eine Möglichkeit, die (meiste?) USB-Devices
auszulesen.
Nur wirklich funktionierende Hinweise für BASIC habe ich nicht gefunden.
Es müßte auch mit den API's gehen, doch auch dafür habe ich keine
funktionierenden Beispiele für die Suche nach angeschlossenen USB-Devices
gefunden. Auch weiß ich nicht, was in die Struktur Guid einzutragen ist,
damit man zB mit HidD_GetHidGuid ein bestimmtes USB-Device findet.
Aber eigentlich weiß ich zu wenig über diese Materie.
Microsofts MSDN bietet eine Dokumentation an, diese enthält aber keine
weiterführenden Beispiele.
Es gibt eine große Anzahl von Firmen, die Libraries (auch gratis) anbieten,
mit denen man sich durch die USB-Devices hanteln kann. Allerdings sind die
meisten davon für C, C++, C#. Und ich kann nicht erwarten, daß diese auf
anderen Rechnern installiert sind. Es müßte ja mit Bordmitteln von VS gehen.
Kann mir jemand Dokumentationen und/oder funktionierende Beispiele benennen,
die mir weiterhelfen?
Irgendwie habe ich den Eindruck, daß die Ratgeber mehr herumreden als mit
Wissen glänzen.
Auf die Frage nach dem Finden der VID und PID wird zB. gemeint "Das
**müßte** eigentlich mit WMI gehen". No comment.
Mit bestem Dank im Voraus
Wolfgang
Aufrund deiner Frage habe ich heute selbst mal den halben Tag mit der
Angelegenheit beschäftigt da ich diesbezüglich auch noch völlig
"blank war".
Es kommt jetzt natürlich darauf an, was du genau wissen willst.
Unten zunächst einmal der Code zum Auflisten der HID-Geräte.
Für die USB-Geräte - das sind i.d.R. die USB-Controller - musst
du GUID_DEVCLASS_USB verwenden (s. auskommentierte Zeile).
Die GUIDs weiterer "Setup Classes" findest du hier:
http://msdn.microsoft.com/en-us/library/ff553428(VS.85).aspx
Imports System.Runtime.InteropServices
Imports System.Diagnostics
Friend Class Main
Const ERROR_NO_MORE_ITEMS As Integer = 259
Const DIGCF_DEFAULT As UInt32 = 1
Const DIGCF_PRESENT As UInt32 = 2
Const DIGCF_ALLCLASSES As UInt32 = 4
Const DIGCF_PROFILE As UInt32 = 8
Const DIGCF_DEVICEINTERFACE As UInt32 = &H10
<StructLayout(LayoutKind.Sequential)> _
Structure SP_DEVINFO_DATA
Public Size As Int32
Public guid As Guid
Public devInst As UInt32
Public Reserved As UIntPtr
End Structure
Shared ReadOnly INVALID_HANDLE_VALUE As IntPtr = New IntPtr(-1)
Shared ReadOnly GUID_DEVCLASS_USB As Guid = New Guid("36fc9e60-c465-11cf-8056-444553540000")
Shared ReadOnly GUID_DEVCLASS_HID As Guid = New Guid("745a17a0-74d3-11d0-b6fe-00a0c90f57da")
Declare Auto Function SetupDiGetClassDevs Lib "setupapi.dll" ( _
<[In]()> ByVal Classguid As IntPtr, _
<[In](), MarshalAs(UnmanagedType.LPTStr)> ByVal Enumerator As String, _
<[In]()> ByVal hWndParent As IntPtr, _
<[In]()> ByVal Flags As UInt32) _
As IntPtr
Declare Auto Function SetupDiGetClassDevs Lib "setupapi.dll" ( _
<[In]()> ByRef Classguid As Guid, _
<[In](), MarshalAs(UnmanagedType.LPTStr)> ByVal Enumerator As String, _
<[In]()> ByVal hWndParent As IntPtr, _
<[In]()> ByVal Flags As UInt32) _
As IntPtr
Declare Auto Function SetupDiDestroyDeviceInfoList Lib "setupapi.dll" ( _
<[In]()> ByVal DeviceInfoSet As IntPtr) _
As Boolean
Declare Auto Function SetupDiEnumDeviceInfo Lib "setupapi.dll" ( _
<[In]()> ByVal DeviceInfoSet As IntPtr, _
<[In]()> ByVal MemberIndex As UInt32, _
<Out()> ByRef DeviceInfoData As SP_DEVINFO_DATA) _
As Boolean
Declare Auto Function SetupDiGetDeviceInstanceId Lib "setupapi.dll" ( _
<[In]()> ByVal DeviceInfoSet As IntPtr, _
<[In]()> ByRef DeviceInfoData As SP_DEVINFO_DATA, _
<[Out]()> ByVal DeviceInstanceId As Text.StringBuilder, _
<[In]()> ByVal DeviceInstanceIdSize As UInt32, _
<[Out]()> ByRef RequiredSize As UInt32 _
) As Boolean
Shared Sub Main()
Dim hDevInfo = SetupDiGetClassDevs(GUID_DEVCLASS_USB, "USB", IntPtr.Zero, DIGCF_PRESENT)
'Dim hDevInfo = SetupDiGetClassDevs(GUID_DEVCLASS_HID, Nothing, IntPtr.Zero, DIGCF_PRESENT)
If hDevInfo = INVALID_HANDLE_VALUE Then
ThrowWin32Exception("SetupDiGetClassDevs")
Else
Try
Do
Dim MemberIndex As UInt32
Dim DeviceInfo As SP_DEVINFO_DATA
DeviceInfo.Size = Marshal.SizeOf(GetType(SP_DEVINFO_DATA))
If SetupDiEnumDeviceInfo(hDevInfo, MemberIndex, DeviceInfo) Then
Dim RequiredSize As UInt32
Dim DeviceInstanceID As New Text.StringBuilder
DeviceInstanceID.Length = 500
If SetupDiGetDeviceInstanceId(hDevInfo, DeviceInfo, DeviceInstanceID, CUInt(DeviceInstanceID.Capacity), RequiredSize) Then
Debug.WriteLine("Device instance id: " & DeviceInstanceID.ToString)
Else
ThrowWin32Exception("SetupDiGetDeviceInstanceId")
End If
Else
Dim Win32Error = Marshal.GetLastWin32Error
If Win32Error = ERROR_NO_MORE_ITEMS Then
Exit Do
Else
ThrowWin32Exception(Win32Error, "SetupDiEnumDeviceInfo")
End If
End If
MemberIndex += 1UI
Loop
Finally
If Not SetupDiDestroyDeviceInfoList(hDevInfo) Then
ThrowWin32Exception("SetupDiDestroyDeviceInfoList")
End If
End Try
End If
End Sub
Shared Sub ThrowWin32Exception(ByVal Location As String)
ThrowWin32Exception(Marshal.GetLastWin32Error, Location)
End Sub
Shared Sub ThrowWin32Exception(ByVal [error] As Integer, ByVal Location As String)
Throw New ComponentModel.Win32Exception([error], "Error at " & Location)
End Sub
End Class
--
Armin
Oder besser hier:
http://msdn.microsoft.com/en-us/library/ff553419(VS.85).aspx
--
Armin
Mir scheint, da� HID ein noch unbeackertes Terrain ist.
Weder in .NET noch in jenen Varianten, die unmittelbar mit den Win-API?s
arbeiten.
Viele Fragen im Netz, aber wenig brauchbare Antworten.
Die Doku in VB ist h�chst akademisch und ohne Beispiele, die meist mehr
sagen als alles �brige.
Eine Doku dazu ist mir aufgefallen: http://www.lvr.com/usbc.htm
Darauf gesto�en bin ich, weil ich ermitteln mu�, welche USB-Massenspeicher
als Verzeichnisse gemountet sind.
Wenn sie als Laufwerke eingebunden sind ist es ja einfach.
Hoffentlich geht das mit HID �berhaupt.
Jedenfalls besten Dank f�r Deine M�hewaltung.
Wolfgang
Ich habe Newsgroups schon immer vor allem auf diese Weise als
Fortbildungseinrichtung verstanden. :) Ich steige nur dann tiefer
ein, wenn es mich auch selbst interessiert.
> Mir scheint, daß HID ein noch unbeackertes Terrain ist.
> Weder in .NET noch in jenen Varianten, die unmittelbar mit den Win-API?s
> arbeiten.
> Viele Fragen im Netz, aber wenig brauchbare Antworten.
> Die Doku in VB ist höchst akademisch und ohne Beispiele, die meist mehr
> sagen als alles übrige.
>
> Eine Doku dazu ist mir aufgefallen: http://www.lvr.com/usbc.htm
>
> Darauf gestoßen bin ich, weil ich ermitteln muß, welche USB-Massenspeicher
> als Verzeichnisse gemountet sind.
Und bist du damit schon weitergekommen? Werde da heute auch mal
nachforschen (aber später erst). Letzter Stand war, dass ich per
DeviceIOControl mit ControlCode=IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
angewandt auf "\\.\K:" (wobei K: ein USB-Stick ist) nur die
Rückmeldung "nicht unterstützt" (o.ä.) bekommen habe.
Bei dir wäre es dann die andere Richtung vom physikalischen Gerät
ausgehend.
Wie gesagt, werde da mal weitersuchen....
> Wenn sie als Laufwerke eingebunden sind ist es ja einfach.
> Hoffentlich geht das mit HID überhaupt.
Was ist denn gegeben und was willst du herausfinden? Bei USB
verstehe ich dein Ansinnen aber bei HID nicht ganz.
--
Armin
"Armin Zingler" <az.n...@freenet.de> wrote in message
news:8s4j4l...@mid.uni-berlin.de...
> Am 17.02.2011 09:18, schrieb Wolfgang Badura:
>
> Bei dir wäre es dann die andere Richtung vom physikalischen Gerät
> ausgehend.
>
Genau!
Ein USB-Stick wurde vom Admin als Verzeichnis gemountet.
In welches?
In der Registry gibt es einen Zweig
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\CPC\LocalMOF
F:\Hama\CF\
F:\Hama\SD\
F:\Hama\xD\
F:\SanDisk\
Dort stehen Die Verzeichnisse drin, aber ich fand bisher (noch) keinen
Zusammenhang zum Stick.
>
> Wie gesagt, werde da mal weitersuchen....
>
>
>> Wenn sie als Laufwerke eingebunden sind ist es ja einfach.
>> Hoffentlich geht das mit HID überhaupt.
>
> Was ist denn gegeben und was willst du herausfinden? Bei USB
> verstehe ich dein Ansinnen aber bei HID nicht ganz.
Wenn Sie als eigenes Laufwerk erscheinen, wie zB "G:\" dann gehts ja mit der
WMI, da finde ich auch Vid und Pid problemlos.
Wenn aber als Verzeichnis? Ich dachte, daß dies vielleicht mit dem HID geht.
Mein vielleicht nicht ganz unwesentlicher Fortschritt war bisher, mittels
WMI und Registry die Vid und Pid
aller USB-Geräte, soweit vorhanden, zu ermitteln. Und jetzt gehts nicht mehr
weiter.
Damit im Zusammenhang habe ich ein weiteres Problem geortet,
für welches ich hier aber einen neuen Thread öffnen werde.
Noch eine Frage: Gibt es ein Forum für VB Net, in dem ich Dich ev. auch
wiederfinden kann?
Danke,
Wolfgang
Ich weiᅵ gar nicht, ob diese Info in dieser Richtung ᅵberhaupt
verfᅵgbar ist. Ich denke eher, dass man anhand des gemounteten
Verzeichnisses herausfinden kann, um welches Volume es sich
handelt.
> In der Registry gibt es einen Zweig
>
> HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\CPC\LocalMOF
> F:\Hama\CF\
> F:\Hama\SD\
> F:\Hama\xD\
> F:\SanDisk\
> Dort stehen Die Verzeichnisse drin, aber ich fand bisher (noch) keinen
> Zusammenhang zum Stick.
>
>>
>> Wie gesagt, werde da mal weitersuchen....
>>
>>
>>> Wenn sie als Laufwerke eingebunden sind ist es ja einfach.
>>> Hoffentlich geht das mit HID ᅵberhaupt.
>>
>> Was ist denn gegeben und was willst du herausfinden? Bei USB
>> verstehe ich dein Ansinnen aber bei HID nicht ganz.
>
> Wenn Sie als eigenes Laufwerk erscheinen, wie zB "G:\" dann gehts ja mit der
> WMI, da finde ich auch Vid und Pid problemlos.
> Wenn aber als Verzeichnis? Ich dachte, daᅵ dies vielleicht mit dem HID geht.
> Mein vielleicht nicht ganz unwesentlicher Fortschritt war bisher, mittels
> WMI und Registry die Vid und Pid
> aller USB-Gerᅵte, soweit vorhanden, zu ermitteln. Und jetzt gehts nicht mehr
> weiter.
Mit den Registry-Zugriffen und auch mit WMI habe ich es nicht so.
Ich verwende lieber (auch) die API.
Vorhin bin ich noch bis hierher gekommen:
http://msdn.microsoft.com/en-us/library/aa365733(VS.85).aspx
Vielleicht hilft das schon weiter. Ich wollte zuvor erst einmal
herausfinden, wieviele "physical disks" es ᅵberhaupt gibt.
Ich habe nirgends etwas dazu gefunden. Die einzig brauchbare
Antwort von einem MVP im Bereich WDK war das, was ich schon
vermutet hatte: Mit der Funktion SetupDiGetClassDevs und
der GUID fᅵr die Klasse "DiskDrives" lᅵsst sich immerhin
die Anzahl feststellen. Das ist erforderlich, wenn man
anschlieᅵend mit CreateFile("\\.\PhysicalDrive#") alle
physikalischen Laufwerke durchgehen will. Fᅵr jedes Laufwerk
lassen sich dann mit DeviceIOControl und IOCTL_DISK_GET_DRIVE_LAYOUT_EX
die Partitionsinformationen ermitteln:
http://msdn.microsoft.com/en-us/library/aa365173(VS.85).aspx
Weiter bin ich noch nicht gekommen.
> Damit im Zusammenhang habe ich ein weiteres Problem geortet,
> fᅵr welches ich hier aber einen neuen Thread ᅵffnen werde.
>
> Noch eine Frage: Gibt es ein Forum fᅵr VB Net, in dem ich Dich ev. auch
> wiederfinden kann?
Nur "nebenan" in m.p.dotnet.languages.vb
In einem Forum bin ich nicht. Ich hatte nach Abschaltung des
MSFT Newsservers keine Lust, mich dazu nᅵtigen zu lassen, der
privaten MSFT Community beizutreten.
Solange es die m.p-Gruppen auf irgendeinem Server gibt, werde ich
sie auch lesen. Auᅵerdem de.comp.lang.misc. Ein Eintrag auf Einrichtung
einer Gruppe fᅵr VB.Net unter der de.comp-Hierarchie wurde gestellt,
ich muss aber zugeben, dass ich den Verlauf nicht weiter verfolgt hatte.
--
Armin
Also, Stand der Dinge:
1. Mit FindFirstVolume/FindNextVolume alle "unique volume names" ermitteln
Sie sind im Format \\?\Volume{GUID}\
2. Fᅵr jedes gefundenen Volumes:
FindFirstVolumeMountPoint/FindNextVolumeMountPoint aufrufen. Wenn du
das fᅵr das Volume, das auch den Buchstaben F:\ trᅵgt, durchfᅵhrst,
bekommst du die Verzeichnisse
- Hama\CF\
- Hama\SD\
- usw
3. ᅵbergib "\\?\Volume{GUID}\Hama\CF\" (usw)
an die Funktion GetVolumeNameForVolumeMountPoint. Ergebnis
ist das Volume, das du gemountet hast, also z.B. das auf
dem USB-Stick.
Die Richtung ist also, wie schon vermutet, eine andere:
Alle gemounteten Verzeichnisse ermitteln und nachprᅵfen, woher
sie kommen. Du musst nur die sammeln, die vom USB-Stick stammen.
Bleibt nur die Frage: Woran willst du den USB-Stick identifizieren?
Was ist also gegeben? Ein Laufwerksbuchstabe? Wenn ja, dann
mᅵsstets du nur fᅵr den LW-Buchstaben GetVolumeNameForVolumeMountPoint
aufrufen und hast somit den "unique volume name". Den musst
du dann mit den eindeutigen Volume-Namen aller gefundenen
Mount points vergleichen. Die gefundenen Mountpoints sind dann
die des USB-Sticks.
Um dann vom Volume aus auch noch das physikalische Device
zu ermitteln, mᅵsstest du DeviceIOControl mit
ControlCode=IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
aufrufen. Da sich ein Volume theoretisch ᅵber mehrere
physikalische Disks erstrecken kann, wᅵrde es auch hier
in diese Richtung funktionieren.
So, mehr war heute nicht drin. ;-)
(Code habe ich auch, aber der sieht sehr, ᅵh, experimentell
aus.)
--
Armin
> Mit den Registry-Zugriffen und auch mit WMI habe ich es nicht so.
> Ich verwende lieber (auch) die API.
Nachdem ich damit schon oft arbeiten mußte, ist mir das ziemlich geläufig
geworden.
Denn auch in VBS-Skripts läßt sich das einfach umsetzen. Und nicht überall
sind alle
zB. VB6 Controls registriert. Manchmal mit dem Killbit nach irgend einem Win
Update versehen.
VBS gibt es praktisch auf allen Windowsrechnern sicher ab XP.
>
> Vorhin bin ich noch bis hierher gekommen:
> http://msdn.microsoft.com/en-us/library/aa365733(VS.85).aspx
>
> Vielleicht hilft das schon weiter. Ich wollte zuvor erst einmal
> herausfinden, wieviele "physical disks" es überhaupt gibt.
> Ich habe nirgends etwas dazu gefunden. Die einzig brauchbare
> Antwort von einem MVP im Bereich WDK war das, was ich schon
> vermutet hatte: Mit der Funktion SetupDiGetClassDevs und
> der GUID für die Klasse "DiskDrives" lässt sich immerhin
> die Anzahl feststellen. Das ist erforderlich, wenn man
> anschließend mit CreateFile("\\.\PhysicalDrive#") alle
> physikalischen Laufwerke durchgehen will. Für jedes Laufwerk
> lassen sich dann mit DeviceIOControl und IOCTL_DISK_GET_DRIVE_LAYOUT_EX
> die Partitionsinformationen ermitteln:
>
SetupDiGetClassDevs ist mir geläufig.
Es gibt das WMI-Äquivalent
Set wmiServices = GetObject _
("winmgmts:{impersonationLevel=Impersonate}!//" & strComputer)
Set wmiDiskDrives = wmiServices.ExecQuery _
("SELECT * FROM Win32_DiskDrive")
für die Drives,
Set wmiDiskPartitions = wmiServices.ExecQuery _
("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & _
strEscapedDeviceID & """} WHERE AssocClass = " & _
"Win32_DiskDriveToDiskPartition")
für die auf den Disks sich befindlichen Partitionen.
Die Größe in TB ist in VBS auch kein Problem, in den entsprechenden API?s
leider schon.
>
> Nur "nebenan" in m.p.dotnet.languages.vb
> In einem Forum bin ich nicht. Ich hatte nach Abschaltung des
> MSFT Newsservers keine Lust, mich dazu nötigen zu lassen, der
> privaten MSFT Community beizutreten.
Ist auch widerlich.
Die Werbung, das Auffinden der eigenen Postings, die unübersichtliche
Präsentation usf.
Nur hat mein Provider aon diese NG noch nicht im Angebot.
Muß ich wieder ein Mail senden, sich darum zu kümmern.
Deswegen auch meine Frage.
Wolfgang
An VID PID und, falls die Tests das ergeben, ev. die Seriennummer.
> Was ist also gegeben? Ein Laufwerksbuchstabe?
Leider ist mir nur VID, PID und die Seriennummer bekannt.
Soweit bin ich schon gekommen, daß diese Daten auf allen Rechnern dieselben
sind.
Das Verzeichnis in welchen sie möglicherweise gemountet eben sind nicht.
> Wenn ja, dann
> müsstets du nur für den LW-Buchstaben GetVolumeNameForVolumeMountPoint
> aufrufen und hast somit den "unique volume name". Den musst
> du dann mit den eindeutigen Volume-Namen aller gefundenen
> Mount points vergleichen. Die gefundenen Mountpoints sind dann
> die des USB-Sticks.
>
> Um dann vom Volume aus auch noch das physikalische Device
> zu ermitteln, müsstest du DeviceIOControl mit
> ControlCode=IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
> aufrufen. Da sich ein Volume theoretisch über mehrere
> physikalische Disks erstrecken kann,
Bei Sticks eher nicht mehr. ;-)
> würde es auch hier
> in diese Richtung funktionieren.
Das werde ich so mal ausprobieren.
Ist ein wirklich interessanter Ansatz.
Hoffentlich habe ich Deine Zeit nicht schon über die Maßen strapaziert.
Besten Dank für Deine Unterstützung.
Wolfgeng.
:) Klar, nur die allgemeinen Strukturen erlauben das
auch wenn es im konkreten Fall nicht zutrifft.
Alle Einheiten wie Devices, Disks, Partitionen, Volumes,
Mounting Points, etc unter einen Hut und in Zusammenhang
zu bringen, ist eben doch nicht so einfach, wie es zunᅵchst
scheint.
Wobei ich noch nicht am Mangel an Dokumentation scheitere,
sondern es einfach nur ein Gebiet ist, mit dem ich mich
bisher noch nicht (programmatisch) beschᅵftigt hatte und es
deswegen sehr viel zu lesen gibt. Zumal Vieles auch aus
unterschiedlichen Bereichen der Doku zusammengesucht werden
muss.
Dass die VID/PID eine Rolle spielt, wusste ich ja schon,
aber jetzt werde ich mal suchen, wie man anhand derer
zu den Infos kommt. Meine Annahme, dass ich durch die Auflistung
der "DiskDrives" an die Nummern der "PhysicalDrives 0-n" komme,
war ja falsch. Richtig sind wohl die Nummern, wie sie auch
in der Datentrᅵgerverwaltung von Windows ("Datentrᅵger XY")
zu sehen sind. Na ich schau mal.
> Hoffentlich habe ich Deine Zeit nicht schon ᅵber die Maᅵen strapaziert.
Also ich finde das Thema momentan ziemlich interessant! Wie gesagt,
sonst wᅵrde ich es auch nicht machen.
> Besten Dank fᅵr Deine Unterstᅵtzung.
Gerne doch.
--
Armin
Ich bleib jetzt mal weiter auf dem Gebiet der API-Aufrufe aktiv.
Wᅵre ja gelacht...!
>> In einem Forum bin ich nicht. Ich hatte nach Abschaltung des
>> MSFT Newsservers keine Lust, mich dazu nᅵtigen zu lassen, der
>> privaten MSFT Community beizutreten.
>
> Ist auch widerlich.
> Die Werbung, das Auffinden der eigenen Postings, die unᅵbersichtliche
> Prᅵsentation usf.
> Nur hat mein Provider aon diese NG noch nicht im Angebot.
> Muᅵ ich wieder ein Mail senden, sich darum zu kᅵmmern.
> Deswegen auch meine Frage.
Mich hat eigentlich eher die Tatsache des privaten Clubs
an sich gestᅵrt und die anfangs erforderliche Zustimmung
zu irgendwelchen Konditionen hat mich dann ganz abgeschreckt.
Nicht, dass ich nicht auch sonst wᅵsste, wie ich mich zu
benehmen hᅵtte, sondern aus Prinzip.
--
Armin
"Armin Zingler" <az.n...@freenet.de> wrote in message
news:8s62od...@mid.uni-berlin.de...
> :) Klar, nur die allgemeinen Strukturen erlauben das
> auch wenn es im konkreten Fall nicht zutrifft.
>
> Alle Einheiten wie Devices, Disks, Partitionen, Volumes,
> Mounting Points, etc unter einen Hut und in Zusammenhang
> zu bringen, ist eben doch nicht so einfach, wie es zunächst
> scheint.
>
> Wobei ich noch nicht am Mangel an Dokumentation scheitere,
> sondern es einfach nur ein Gebiet ist, mit dem ich mich
> bisher noch nicht (programmatisch) beschäftigt hatte und es
> deswegen sehr viel zu lesen gibt. Zumal Vieles auch aus
> unterschiedlichen Bereichen der Doku zusammengesucht werden
> muss.
>
> Dass die VID/PID eine Rolle spielt, wusste ich ja schon,
> aber jetzt werde ich mal suchen, wie man anhand derer
> zu den Infos kommt. Meine Annahme, dass ich durch die Auflistung
> der "DiskDrives" an die Nummern der "PhysicalDrives 0-n" komme,
> war ja falsch. Richtig sind wohl die Nummern, wie sie auch
> in der Datenträgerverwaltung von Windows ("Datenträger XY")
> zu sehen sind. Na ich schau mal.
>
Ein wenig kann ich so einem höchst versierten Spezialisten vielleicht doch
helfen:
Das VBS-Skript, mit welchem ich ua. die Daten der Massenspeicher ermittle
habe ich unter
Upload Link:
http://www.file-upload.net/download-3224081/NW_WMI_Infos.vbs.html
hochgeladen.
Wenn ich von einem PC das Wichtigste wissen möchte, so sende ich dieses
Skript
und ersuche um Rücksendung des Ergebnisses.
Ich bin nach Adaption der Declares der API?s und der Strukturen
soweit gekommen, daß es keine Fehler bis zu jenem Punkt gibt, an dem ich die
USB-Devices Enumeriere.
Ich erhalte aber beim Aufruf der API SetupDiEnumDeviceInterfaces 0.
Ob es für USB Massenspeicher keine Werte gibt, oder der Aufruf ins Leere
geht weiß ich natürlich nicht,
da ich neben den USBSTORes keine USB-Devices besitze: keine Tastatur, Maus,
Fernsteuerung etc.
Fehler treten bis dorthin jedenfalls nicht auf.
Ich werde am Nachmittag versuchen beim Media-Markt ein Device zu erstehen,
das ich nicht nur für diese Tests verwenden kann: vielleicht einen
MultiDrucker,Scanner,Fax für meine Frau.
Aber allein die Bereinigung der Strukturen und Declares war ein
befriedigendes
Erlebnis als das Kompilieren und Tracen bis zum Punkt des
Nichtvorhandenseins von Devices funktionierte.
Ich möchte mich erneut für Deine Bemühungen bedanken.
So war auch meine Nacht lang.
Hoffentlich strapazierst Du Dich wegen meiner Anfrage nicht zu sehr.
Danke
Wolfgang
Dieses Gebiet ist für mich ja auch Neuland. Danke auch für den Link,
dennoch werde ich mich weiter ins WDK/SDK einlesen.
> Ich erhalte aber beim Aufruf der API SetupDiEnumDeviceInterfaces 0.
Ging mir erst genau so. Herausgefunden habe ich: Das Ding ist, dass nicht
jedes Device jedes Interface anbietet. Wenn ich bei SetupDiGetClassDevs
die Setup-Class "disk drive" hole, dann gibt es davon kein einziges
Devices, das die Interface-Class "disk" anbietet. Ergo: 0.
Wenn man aber bei SetupDiGetClassDevs als ersten Parameter die
gewünschte Interface-Class-GUID übergibt, z.B. GUID_DEVINTERFACE_DISK
und gleichzeitig als letzten Parameter DIGCF_DEVICEINTERFACE
angibt, dann bekommt man auch nur devices geliefert, die das
Interface anbieten. Ergo liefert auch SetupDiEnumDeviceInterfaces
etwas zurück.
Wobei die Info aus SetupDiEnumDeviceInterfaces lediglich die Flags
sind (Active, Default oder Removed). Nicht sehr wertvoll.
> Hoffentlich strapazierst Du Dich wegen meiner Anfrage nicht zu sehr.
Auslöser <> Verantwortlicher. :) Nein, mich interessiert es selbst sehr.
--
Armin
Heute Nacht ist mir einfach so eingefallen, daß es mit der GUID innerhalb
des Aufrufs
der API SetupDiGetClassDevs zusammenhängen muß. Richtig, wie Deine Antwort
beweist.
Bin gerade dabei mit der Information GUID_DEVINTERFACE_DISK und
DIGCF_DEVICEINTERFACE weiter zu probieren. Leider eben mehr probieren als
gezielt zu handeln.
Aber auch dabei kann ich was dazulernen.
Danke
Wolfgang
Aber ich komme über die Ermittlung der Devcedetails nicht hinaus.
Wahrscheinlich ist die folgende Deklaration falsch:
Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib
"setupapi.dll" _
Alias "SetupDiGetDeviceInterfaceDetailW" ( _
ByVal hDevInfo As IntPtr, _
ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
ByVal deviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA, _
ByVal deviceInterfaceDetailDataSize As Int32, _
ByRef requiredSize As Int32, _
ByVal deviceInfoData As SP_DEVINFO_DATA) As Boolean
Schon der erste Aufruf
Dim ptrDeviceHandle As IntPtr = DeviceHandle
bRet = SetupDiGetDeviceInterfaceDetail( _
ptrDeviceHandle, _
spDeviceInterfaceData, _
SPDeviceInterfaceDetailData, 0, Needed, _
spDevInfoData)
ergibt in bRet False
Ich habe die Definitionen x-mal angepasst. aber erfolglos.
Wolfgang
Die Parameter deviceInterfaceDetailData und deviceInfoData müssen ByRef sein.
Ansonsten entspricht es auch meiner Deklaration.
Wenn du "Auto" verwendest, kannst du dir den Alias-Abschnitt sparen.
--
Armin
- ptrDeviceHandle ist das Handle des Device Info Set, das du
per SetupDiGetClassDevs zurückbekommst?
- Und statt der 0 müsstest du eigentlich die Größe von SPDeviceInterfaceDetailData
übergeben.
- Wie hast du den Typ von SPDeviceInterfaceDetailData deklariert?
- Außerdem muss SPDeviceInterfaceDetailData.size vorher richtig gesetzt
worden sein. Wenn man sich das vierte Posting von unten auf dieser Seite
http://developer.garmin.com/forum/viewtopic.php?p=762&sid=7fe7dda9a1d3e9279947210fa25407f7
ansieht, scheint 8 der richtige Wert für 64-Bit-Plattformen
und 5 der richtige für 32-Bit-Plattformen zu sein.
Es steht sogar ein Kommentar dabei, dass das so ist.
Ich habe das einfch mal ganz dumm übernommen.
- spDevInfoData.Size mus natürlich auch richtig gesetzt sein.
Die Ausgabe der gesamten Enumerierung für die "Volumes" sieht wie folgt aus.
Unter "Details" steht die Rückgabe von SPDeviceInterfaceDetailData.
Devices:
#0
Class Description: DVD/CD-ROM-Laufwerke
Device instance id: IDE\CDROMHL-DT-ST_DVD-ROM_GDR8164B_______________0L06____\6&1787D843&0&0.0.0
Interfaces:
#0:
InterfaceClassGuid: 53f5630d-b6bf-11d0-94f2-00a0c91efb8b
Flags : Active
Details:
Device path = \\?\ide#cdromhl-dt-st_dvd-rom_gdr8164b_______________0l06____#6&1787d843&0&0.0.0#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}
#1
Class Description: DVD/CD-ROM-Laufwerke
Device instance id: IDE\CDROMHL-DT-ST_DVDRAM_GSA-4163B_______________A104____\6&1787D843&0&0.1.0
Interfaces:
#0:
InterfaceClassGuid: 53f5630d-b6bf-11d0-94f2-00a0c91efb8b
Flags : Active
Details:
Device path = \\?\ide#cdromhl-dt-st_dvdram_gsa-4163b_______________a104____#6&1787d843&0&0.1.0#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}
#2
Class Description: Speichervolumes
Device instance id: STORAGE\VOLUME\_??_USBSTOR#DISK&VEN_GENERIC&PROD_FLASH_HS-CF&REV_5.39#080420200041&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
Interfaces:
#0:
InterfaceClassGuid: 53f5630d-b6bf-11d0-94f2-00a0c91efb8b
Flags : Active
Details:
Device path = \\?\storage#volume#_??_usbstor#disk&ven_generic&prod_flash_hs-cf&rev_5.39#080420200041&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}
[usw]
--
Armin
Hätte ich nicht machen sollen. Habe es jetzt mal für 32-Bit kompiliert.
Der richtige Wert ist 6 (nicht 5). Ist aber auch logisch, denn die
Deklaration der Struktur ist ja:
DWORD cbSize;
TCHAR DevicePath[ANYSIZE_ARRAY];
TCHAR ist 1 Byte bei 32 Bit und 2 Bytes bei 64 Bit. ANYSIZE_ARRAY
ist mit 1 deklariert. Da 1 Zeichen plus der nul-Terminator Platz
haben müssen, wäre das dann
- 32 Bit: 4 + 2*1 = 6
- 64 Bit: 4 + 2*2 = 8
Somit also:
dim Details as SP_DEVICE_INTERFACE_DETAIL_DATA
Details.Size = If(IntPtr.Size = 4, 6UI, 8UI)
--
Armin
> - Und statt der 0 müsstest du eigentlich die Größe von SPDeviceInterfaceDetailData
> übergeben.
Um zuerst die Größe zu ermitteln, kann es natürlich die 0 sein. Dann
muss aber auch der Parameter "DeviceInterfaceDetailData" IntPtr.zero sein.
--
Armin
Hier meine Definitionen nach dem letzten Umbau
Public Const BUFFER_SIZE As Short = 255
Public Const DIGCF_PRESENT As Int32 = (2)
Public Const DIGCF_DEVICEINTERFACE = &H10
Public Const GUID_DEVINTERFACE_DISK =
"{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}"
Public Structure SP_DEVINFO_DATA
Public cbSize As Int32
Public InterfaceClassGuid As Guid
Public Flags As Int32
Public Reserved As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential, pack:=2)> _
Public Structure SP_DEVICE_INTERFACE_DATA
Public cbSize As Int32
Public interfaceClassGuid As Guid
Public flags As Int32
Private reserved As UIntPtr
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto, pack:=1)> _
Public Structure SP_DEVICE_INTERFACE_DETAIL_DATA
Public cbSize As Int32
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=BUFFER_SIZE)> _
Public DevicePath As String
End Structure
Declare Auto Function SetupDiGetClassDevs Lib _
"setupapi.dll" Alias "SetupDiGetClassDevsA" _
(ByRef GuidPtr As Guid, _
ByVal EnumPtr As IntPtr, _
ByVal HwndParent As Int32, _
ByVal Flags As Int32) _
As Int32
Public Declare Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll" ( _
ByVal DeviceInfoSet As Int32, _
ByVal DeviceInfoData As Int32, _
ByRef InterfaceClassGuid As Guid, _
ByVal MemberIndex As Int32, _
ByRef DeviceInterfaceData As SP_DEVINFO_DATA) _
As Boolean
Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib
"setupapi.dll" _
Alias "SetupDiGetDeviceInterfaceDetailW" ( _
ByRef hDevInfo As Int32, _
ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
ByRef deviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA, _
ByVal deviceInterfaceDetailDataSize As Int32, _
ByRef requiredSize As Int32, _
ByVal deviceInfoData As SP_DEVINFO_DATA) As Boolean
Deklarationen in der Funktion USB_GetSerNums (hier sollen einmal die Devices
ermittelt werden)
.
Dim HidGuid As Guid
Dim spDeviceInterfaceData As New SP_DEVICE_INTERFACE_DATA
Dim spDevInfoData As New SP_DEVINFO_DATA
Dim SPDeviceInterfaceDetailData As New SP_DEVICE_INTERFACE_DETAIL_DATA
Dim Needed As Int32
HidGuid = New Guid(GUID_DEVINTERFACE_DISK)
DeviceHandle = SetupDiGetClassDevs(HidGuid, 0, 0, DIGCF_PRESENT Or
DIGCF_DEVICEINTERFACE)
LenB = Marshal.SizeOf(spDeviceInterfaceData) 'LenB = 28
spDeviceInterfaceData.cbSize = LenB
spDevInfoData.cbSize = LenB
' jetzt aus Deinem Vorschlag
LenB = Marshal.SizeOf(SPDeviceInterfaceDetailData) 'LenB = 514
SPDeviceInterfaceDetailData.cbSize = If(IntPtr.Size = 4, 6UI, 8UI)
MemberIndex = 0
bRetDiEnum = SetupDiEnumDeviceInterfaces(DeviceHandle, 0, HidGuid,
MemberIndex, spDevInfoData)
' das ist der erste Aufruf zwecks Ermittlung der Buffergrößen
bRetDiEnumInterfaceDetail = SetupDiGetDeviceInterfaceDetail( _
DeviceHandle, _
spDeviceInterfaceData, _
SPDeviceInterfaceDetailData, 0, Needed, _
spDevInfoData)
und hier ist auch Schluß
Der Fehler lautet immer "The Handle is invalid."
Vielleicht siehst Du in meinem Code das von mir unwissentlich offenbar gut
versteckte Problem.
Nochmals Danke,
Wolfgang
Als erstes solltest du ganz dringend Option Strict On einschalten.
Erst recht bei solchen Aktionen sind die richtigen Datentypen wichtig.
Momentan kann ich den Code deshalb nicht testen. Beseitige erst mal
die Compilierfehler, und dann schau ich gerne noch mal drüber.
--
Armin
Ich hoffe noch heute berichten zu können.
Allerdings bin ich ab Dienstag für **mindestens** 2 ganze Tage im Spital.
Dann kann ich mich frühestens am Donnerstag, 24.2.2011 wieder melden.
Wolfgang
Alles Gute und viel Erfolg!
--
Armin
Hier nun der ganze Code (mit strict on und ohne Kompilerfehler):
Imports System.Threading
Imports System.Runtime.InteropServices
Public Class Form1
' P/Invoke API
<DllImport("HID.dll")> _
Private Shared Sub HidD_GetHidGuid(ByRef GuidPtr As Guid)
End Sub
Public Const BUFFER_SIZE As Short = 255
Public Const DIGCF_PRESENT As Int32 = (2)
Public Const DIGCF_DEVICEINTERFACE As UInt32 = &H10
Public Const GUID_DEVINTERFACE_DISK As String =
"{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}"
Public Structure SP_DEVINFO_DATA
Public cbSize As Int32
Public InterfaceClassGuid As Guid
Public Flags As Int32
Public Reserved As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential, pack:=2)> _
Public Structure SP_DEVICE_INTERFACE_DATA
Public cbSize As Int32
Public interfaceClassGuid As Guid
Public flags As Int32
Private reserved As UIntPtr
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto, pack:=1)> _
Public Structure SP_DEVICE_INTERFACE_DETAIL_DATA
Public cbSize As UInt32
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=BUFFER_SIZE)> _
Public DevicePath As String
End Structure
Declare Auto Function SetupDiGetClassDevs Lib _
"setupapi.dll" Alias "SetupDiGetClassDevsA" _
(ByRef GuidPtr As Guid, _
ByVal EnumPtr As IntPtr, _
ByVal HwndParent As Int32, _
ByVal Flags As Int32) _
As IntPtr
Public Declare Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll"
( _
ByVal DeviceInfoSet As IntPtr, _
ByVal DeviceInfoData As Int32, _
ByRef InterfaceClassGuid As Guid, _
ByVal MemberIndex As Int32, _
ByRef DeviceInterfaceData As SP_DEVINFO_DATA) _
As Boolean
Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib _
"setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailW" ( _
ByRef hDevInfo As IntPtr, _
ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
ByRef deviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA, _
ByVal deviceInterfaceDetailDataSize As Int32, _
ByRef requiredSize As Int32, _
ByVal deviceInfoData As SP_DEVINFO_DATA) As Boolean
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim HidGuid As Guid
Dim spDeviceInterfaceData As New SP_DEVICE_INTERFACE_DATA
Dim spDevInfoData As New SP_DEVINFO_DATA
Dim SPDeviceInterfaceDetailData As New SP_DEVICE_INTERFACE_DETAIL_DATA
Dim LenB As Int32
Dim Needed As Int32
Dim DeviceHandle As IntPtr
Dim MemberIndex As Integer
Dim bRetDiEnum As Boolean
Dim bRetDiEnumInterfaceDetail As Boolean
HidGuid = New Guid(GUID_DEVINTERFACE_DISK)
DeviceHandle = SetupDiGetClassDevs(HidGuid, IntPtr.Zero, 0,
DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE)
LenB = Marshal.SizeOf(spDeviceInterfaceData) 'LenB = 28
spDeviceInterfaceData.cbSize = LenB
spDevInfoData.cbSize = LenB
' jetzt aus Deinem Vorschlag
LenB = Marshal.SizeOf(SPDeviceInterfaceDetailData) 'LenB = 514
SPDeviceInterfaceDetailData.cbSize = If(IntPtr.Size = 4, 6UI, 8UI)
MemberIndex = 0
bRetDiEnum = SetupDiEnumDeviceInterfaces(DeviceHandle, 0, HidGuid,
MemberIndex, spDevInfoData)
Do While bRetDiEnum
' das ist der erste Aufruf zwecks Ermittlung der Buffergrößen
bRetDiEnumInterfaceDetail = SetupDiGetDeviceInterfaceDetail( _
DeviceHandle, _
spDeviceInterfaceData, _
SPDeviceInterfaceDetailData, 0, Needed, _
spDevInfoData)
bRetDiEnum = SetupDiEnumDeviceInterfaces(DeviceHandle, 0, HidGuid,
MemberIndex, spDevInfoData)
Loop
End Sub
End Class
bRetDiEnumInterfaceDetail ist immer noch false.
Do While bRetDiEnum wird 5mal durchlaufen.
Besten Dank
Wolfgang
> bRetDiEnum = SetupDiEnumDeviceInterfaces(DeviceHandle, 0, HidGuid,
> MemberIndex, spDevInfoData)
Hier fehlt natürlich vorher
MemberIndex += 1
Habe die Kopie des Codes zum falschen Zeitpunkt gemacht.
Die Do While Schleife läuft wie schon gesagt 5mal durch.
Wolfgang
Imports System.Threading
Imports System.Runtime.InteropServices
Public Class Form1
' P/Invoke API
<DllImport("HID.dll")> _
Private Shared Sub HidD_GetHidGuid(ByRef GuidPtr As Guid)
End Sub
Public Const BUFFER_SIZE As Short = 255
Public Const DIGCF_PRESENT As Int32 = (2)
Public Const DIGCF_DEVICEINTERFACE As UInt32 = &H10
Public Const GUID_DEVINTERFACE_DISK As String =
"{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}"
Public Const FORMAT_MESSAGE_FROM_SYSTEM As Int32 = &H1000
Public Structure SP_DEVINFO_DATA
Public cbSize As UInt32
Public UInt32 As Guid
Public Flags As Int32
Public Reserved As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential, pack:=2)> _
Public Structure SP_DEVICE_INTERFACE_DATA
Public cbSize As UInt32
Public interfaceClassGuid As Guid
Public flags As Int32
Private reserved As UIntPtr
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto, pack:=1)> _
Public Structure SP_DEVICE_INTERFACE_DETAIL_DATA
Public cbSize As UInt32
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=BUFFER_SIZE)> _
Public DevicePath As String
End Structure
Declare Auto Function SetupDiGetClassDevs Lib _
"setupapi.dll" Alias "SetupDiGetClassDevsA" _
(ByRef GuidPtr As Guid, _
ByVal EnumPtr As IntPtr, _
ByVal HwndParent As Int32, _
ByVal Flags As Int32) _
As IntPtr
Public Declare Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll"
( _
ByVal DeviceInfoSet As IntPtr, _
ByVal DeviceInfoData As Int32, _
ByRef InterfaceClassGuid As Guid, _
ByVal MemberIndex As Int32, _
ByRef DeviceInterfaceData As SP_DEVINFO_DATA) _
As Boolean
Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib _
"setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailW" ( _
ByRef hDevInfo As IntPtr, _
ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
ByRef deviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA, _
ByVal deviceInterfaceDetailDataSize As Int32, _
ByRef requiredSize As Int32, _
ByVal deviceInfoData As SP_DEVINFO_DATA) As Boolean
Private Declare Function FormatMessage Lib "kernel32" Alias _
"FormatMessageA" ( _
ByVal dwFlags As Int32, _
ByVal lpSource As Int32, _
ByVal dwMessageId As Int32, _
ByVal dwLanguageId As Int32, _
ByVal lpBuffer As String, _
ByVal nSize As Int32, _
ByVal Arguments As Int32) _
As Int32
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim HidGuid As Guid
Dim spDeviceInterfaceData As New SP_DEVICE_INTERFACE_DATA
Dim spDevInfoData As New SP_DEVINFO_DATA
Dim SPDeviceInterfaceDetailData As New SP_DEVICE_INTERFACE_DETAIL_DATA
Dim LenB As UInt32
Dim Needed As Int32
Dim DeviceHandle As IntPtr
Dim MemberIndex As Integer
Dim bRetDiEnum As Boolean
Dim bRetDiEnumInterfaceDetail As Boolean
Dim strAPIDesc As String
Dim strFormat As String
HidGuid = New Guid(GUID_DEVINTERFACE_DISK)
DeviceHandle = SetupDiGetClassDevs(HidGuid, IntPtr.Zero, 0,
DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE)
LenB = CUInt(Marshal.SizeOf(spDeviceInterfaceData)) 'LenB = 28
spDeviceInterfaceData.cbSize = LenB
spDevInfoData.cbSize = LenB
' jetzt aus Deinem Vorschlag
LenB = CUInt(Marshal.SizeOf(SPDeviceInterfaceDetailData)) 'LenB = 514
SPDeviceInterfaceDetailData.cbSize = If(IntPtr.Size = 4, 6UI, 8UI)
MemberIndex = 0
bRetDiEnum = SetupDiEnumDeviceInterfaces(DeviceHandle, 0, HidGuid,
MemberIndex, spDevInfoData)
Do While bRetDiEnum
' das ist der erste Aufruf zwecks Ermittlung der Buffergrößen
bRetDiEnumInterfaceDetail = SetupDiGetDeviceInterfaceDetail( _
DeviceHandle, _
spDeviceInterfaceData, _
SPDeviceInterfaceDetailData, 0, Needed, _
spDevInfoData)
If Not bRetDiEnumInterfaceDetail Then
strAPIDesc = APIErrorDescription(Err.LastDllError)
strFormat = String.Format(" ***Error
SetupDiGetDeviceInterfaceDetail: {0}, {1}", _
Err.LastDllError.ToString,
APIErrorDescription(Err.LastDllError))
lstTrace.Items.Add(strFormat)
Trace.WriteLine(strFormat)
End If
MemberIndex += 1
bRetDiEnum = SetupDiEnumDeviceInterfaces(DeviceHandle, 0, HidGuid,
MemberIndex, spDevInfoData)
Loop
End Sub
' Get Last DLLErr
Public Function APIErrorDescription(ByVal ErrorCode As Int32) As String
Dim strErrDescription As String
Dim lRet As Int32
Dim strFormat As String
APIErrorDescription = ""
strErrDescription = StrDup(255, Chr(0))
Try
lRet = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, _
ErrorCode, 0, strErrDescription, 255, 0)
APIErrorDescription = strErrDescription.Substring(0,
strErrDescription.IndexOf(vbCr))
Catch ex As Exception
strFormat = String.Format(" ***Error
APIErrorDescription({0}: {1}, {2}", _
ErrorCode, Err.Number, Err.Description)
lstTrace.Items.Add(strFormat)
Trace.WriteLine(strFormat)
APIErrorDescription = "Fehler: Kein Rückgabewert für die Funktion
APIErrorDescription"
End Try
End Function
End Class
Hier würde ich noch ein StructLayout hinpacken; sicherheitshalber:
<StructLayout(LayoutKind.Sequential)> _
> Public Structure SP_DEVINFO_DATA
> Public cbSize As Int32
> Public InterfaceClassGuid As Guid
> Public Flags As Int32
> Public Reserved As IntPtr
> End Structure
> <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto, pack:=1)> _
> Public Structure SP_DEVICE_INTERFACE_DETAIL_DATA
> Public cbSize As UInt32
> <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=BUFFER_SIZE)> _
> Public DevicePath As String
> End Structure
Bei SP_DEVICE_INTERFACE_DETAIL_DATA bin ich anders vorgegangen weil
eine Structure mit dynamischer Größe nicht unterstützt wird. Woher
hast du die Info, dass die Längebegrenzung BUFFER_SIZE ist?
Das aber nur nebenbei, denn das ist nicht der Fehler. Habe also
deine Deklaration belassen.
Und wo steht, dass pack=1 sein muss?
> Declare Auto Function SetupDiGetClassDevs Lib _
> "setupapi.dll" Alias "SetupDiGetClassDevsA" _
> (ByRef GuidPtr As Guid, _
> ByVal EnumPtr As IntPtr, _
> ByVal HwndParent As Int32, _
> ByVal Flags As Int32) _
> As IntPtr
Einfach mal meine Deklaration eingefügt: (zwei Überladungen)
Der Unterschied der beiden ist der erste Parameter, damit man
auch NULL (Intptr.Zero) übergeben kann.
Zu den In/Out-Attributen: Wenn ich mir nicht sicher bin, wie das
Standard-Marshalling-Verhalten ist, dann gebe ich die Attribute
an.
Public Declare Auto Function SetupDiGetClassDevs Lib "setupapi.dll" ( _
ByVal Classguid As IntPtr, _
<[In](), MarshalAs(UnmanagedType.LPTStr)> ByVal Enumerator As String, _
ByVal hWndParent As IntPtr, _
ByVal Flags As GetClassDevsFlags) _
As IntPtr
Public Declare Auto Function SetupDiGetClassDevs Lib "setupapi.dll" ( _
<[In]()> ByRef Classguid As Guid, _
<[In](), MarshalAs(UnmanagedType.LPTStr)> ByVal Enumerator As String, _
ByVal hWndParent As IntPtr, _
ByVal Flags As GetClassDevsFlags) _
As IntPtr
Wobei ich zusätzlich den/die/das Enum GetClassDevsFlags deklariert habe:
<Flags()> _
Public Enum GetClassDevsFlags As UInt32
None = 0
[Default] = 1
Present = 2
AllClasses = 4
Profile = 8
DeviceInterface = 16
End Enum
> Public Declare Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll"
> ( _
> ByVal DeviceInfoSet As IntPtr, _
> ByVal DeviceInfoData As Int32, _
> ByRef InterfaceClassGuid As Guid, _
> ByVal MemberIndex As Int32, _
> ByRef DeviceInterfaceData As SP_DEVINFO_DATA) _
> As Boolean
Bei den Pointern musst du aufpassen, denn Int32 ist nur ein Ersatz
auf 32-Bit Systemen. Ergo: zweiter Parameter muss "Byval IntPtr"
sein, oder wie folgt "ByRef SP_DEVINFO_DATA". Der Typ des letzten
Parameters hast du wohl versehentlich als SP_DEVINFO_DATA
deklariert. Somit:
Public Declare Auto Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll" ( _
ByVal hDeviceInfoSet As IntPtr, _
ByVal DeviceInfoData As IntPtr, _
<[In]()> ByRef InterfaceClassGuid As Guid, _
ByVal MemberIndex As UInt32, _
<[In](), [Out]()> ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA _
) As Boolean
> Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib _
> "setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailW" ( _
> ByRef hDevInfo As IntPtr, _
> ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
> ByRef deviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA, _
> ByVal deviceInterfaceDetailDataSize As Int32, _
> ByRef requiredSize As Int32, _
> ByVal deviceInfoData As SP_DEVINFO_DATA) As Boolean
Zu SetupDiGetDeviceInterfaceDetail habe ich diverse Überladungen. Mal
die Variante, die deiner Version am nächsten kommt:
Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib "setupapi.dll" ( _
ByVal hDeviceInfoSet As IntPtr, _
<[In]()> ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
<[In](), [Out]()> ByRef DeviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA, _
ByVal DeviceInterfaceDetailDataSize As UInt32, _
<[Out]()> ByRef RequiredSize As UInt32, _
<[In](), [Out]()> ByRef DeviceInfoData As SP_DEVINFO_DATA _
) As Boolean
Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib "setupapi.dll" ( _
ByVal hDeviceInfoSet As IntPtr, _
<[In]()> ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
ByVal DeviceInterfaceDetailData As IntPtr, _
ByVal DeviceInterfaceDetailDataSize As UInt32, _
<[Out]()> ByRef RequiredSize As UInt32, _
<[In](), [Out]()> ByRef DeviceInfoData As SP_DEVINFO_DATA _
) As Boolean
Die zweite Überladung brauchst du für den erstmaligen Aufruf
zur Ermittlung der Puffergröße, denn dabei musst du IntPtr.Zero
als dritten Parameter übergeben.
> Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
> System.EventArgs) Handles MyBase.Load
> [...]
Nach den Korrekturen sieht's nun wie folgt aus. Zwar
liefert SetupDiGetDeviceInterfaceDetail jetzt immer noch false,
aber nicht mehr mit Marshal.Getlastwin32error = 6 ("ungültiges handle")
sonder mit Fehler 1784, also "insufficient Buffer". Das ist
aber auch richtig, denn du hast ja als Länge 0 übergeben
und bekommst deswegen in "Needed" die benötigte Größe
zurück. Du musst also die Funktion noch einmal mit
der korrekten Puffergröße aufrufen. Steht ja aber auch
schon so in deinem eigenen Kommentar. Darüber, dass
der Funktionswert False ist, kannst du dich also gar
nicht gewundert haben. ;-)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim HidGuid As Guid
Dim spDeviceInterfaceData As New SP_DEVICE_INTERFACE_DATA
Dim spDevInfoData As New SP_DEVINFO_DATA
Dim SPDeviceInterfaceDetailData As New SP_DEVICE_INTERFACE_DETAIL_DATA
Dim LenB As Int32
Dim Needed As UInt32
Dim DeviceHandle As IntPtr
Dim MemberIndex As UInteger
Dim bRetDiEnum As Boolean
Dim bRetDiEnumInterfaceDetail As Boolean
HidGuid = New Guid(GUID_DEVINTERFACE_DISK)
DeviceHandle = SetupDiGetClassDevs(HidGuid, Nothing, IntPtr.Zero, GetClassDevsFlags.Present Or GetClassDevsFlags.DeviceInterface)
LenB = Marshal.SizeOf(spDeviceInterfaceData) 'LenB = 28
spDeviceInterfaceData.cbSize = LenB
spDevInfoData.cbSize = LenB
' jetzt aus Deinem Vorschlag
LenB = Marshal.SizeOf(SPDeviceInterfaceDetailData) 'LenB = 514
SPDeviceInterfaceDetailData.cbSize = If(IntPtr.Size = 4, 6UI, 8UI)
MemberIndex = 0
bRetDiEnum = SetupDiEnumDeviceInterfaces(DeviceHandle, IntPtr.Zero, HidGuid, MemberIndex, spDeviceInterfaceData)
Do While bRetDiEnum
' das ist der erste Aufruf zwecks Ermittlung der Buffergrößen
bRetDiEnumInterfaceDetail = SetupDiGetDeviceInterfaceDetail( _
DeviceHandle, _
spDeviceInterfaceData, _
IntPtr.Zero, 0, Needed, _
spDevInfoData)
bRetDiEnumInterfaceDetail = SetupDiGetDeviceInterfaceDetail( _
DeviceHandle, _
spDeviceInterfaceData, _
SPDeviceInterfaceDetailData, Needed, Needed, _
spDevInfoData)
Debug.Print(SPDeviceInterfaceDetailData.DevicePath)
bRetDiEnum = SetupDiEnumDeviceInterfaces(DeviceHandle, IntPtr.Zero, HidGuid, MemberIndex, spDeviceInterfaceData)
MemberIndex += 1UI
Loop
End Sub
--
Armin
Das hat sich jetzt leider überschnitten. Habe deinen letzten Code
überarbeitet und soeben gepostet. Deine neue Version habe ich
jetzt erst gesehen.
--
Armin
Ich habe Deine beiden Postings noch gelesen.
Machen kann ich jetzt nichts mehr, es ist schon spät geworden und
morgen geht es um 7:00 ab.
Hoffentlich bleibt es bei nur zwei Tagen im Spital.
Danke für Deine sorgfältige Unterstützung.
Wolfgang
Mein behandelnder Spitalsarzt hat mich nach der Erhebung meines
Blubildes wieder nach Hause geschickt!
Ich möge doch in drei Wochen wiederkommen.
Also werkle ich wieder mit Hilfe Deines Postings.
(Übrigens wurde ich noch nie in einem Forum so ausführlich und kompetent
beraten wie von Dir. Vor allem mit so viel Wohlwollen!)
"Armin Zingler" <az.n...@freenet.de> wrote in message
news:8sfq82...@mid.uni-berlin.de...
> Am 21.02.2011 17:30, schrieb Wolfgang Badura:
>
>
> Hier würde ich noch ein StructLayout hinpacken; sicherheitshalber:
>
> <StructLayout(LayoutKind.Sequential)> _
OK.
>
>
>> <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto, pack:=1)>
>> _
>> Public Structure SP_DEVICE_INTERFACE_DETAIL_DATA
>> Public cbSize As UInt32
>> <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=BUFFER_SIZE)> _
>> Public DevicePath As String
>> End Structure
>
> Bei SP_DEVICE_INTERFACE_DETAIL_DATA bin ich anders vorgegangen weil
> eine Structure mit dynamischer Größe nicht unterstützt wird. Woher
> hast du die Info, dass die Längebegrenzung BUFFER_SIZE ist?
1. aus
http://stackoverflow.com/questions/2937585/how-to-open-a-serial-port-by-friendly-name
2. dachte ich, daß ja diese Definition einmal die Daten einer zuerst
unbestimmten Länge aufnehmen können muß.
>
> Und wo steht, dass pack=1 sein muss?
3. aus Sicherheitsgründen ;-), damit zwischen den Strukturbytes keine
padding-bytes lagern. War der Gedanke so falsch?
>
> Einfach mal meine Deklaration eingefügt: (zwei Überladungen)
> Der Unterschied der beiden ist der erste Parameter, damit man
> auch NULL (Intptr.Zero) übergeben kann.
Jetzt ist mir eine weitere Möglichkeit von Überladungen verständlich.
>
> Zu den In/Out-Attributen: Wenn ich mir nicht sicher bin, wie das
> Standard-Marshalling-Verhalten ist, dann gebe ich die Attribute
> an.
Von <[In]() / [Out] Attributen lese ich zum ersten Mal. Danke!
OK.
>> Public Declare Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll"
>> ( _
>> ByVal DeviceInfoSet As IntPtr, _
>> ByVal DeviceInfoData As Int32, _
>> ByRef InterfaceClassGuid As Guid, _
>> ByVal MemberIndex As Int32, _
>> ByRef DeviceInterfaceData As SP_DEVINFO_DATA) _
>> As Boolean
>
> Bei den Pointern musst du aufpassen, denn Int32 ist nur ein Ersatz
> auf 32-Bit Systemen. Ergo: zweiter Parameter muss "Byval IntPtr"
> sein, oder wie folgt "ByRef SP_DEVINFO_DATA".
>
OK.
>Der Typ des letzten
> Parameters hast du wohl versehentlich als SP_DEVINFO_DATA
> deklariert.
Ja. Ich sagte schon "ganz schwindlig".
> Somit:
>
> Public Declare Auto Function SetupDiEnumDeviceInterfaces Lib
> "setupapi.dll" ( _
> ByVal hDeviceInfoSet As IntPtr, _
> ByVal DeviceInfoData As IntPtr, _
> <[In]()> ByRef InterfaceClassGuid As Guid, _
> ByVal MemberIndex As UInt32, _
> <[In](), [Out]()> ByRef DeviceInterfaceData As
> SP_DEVICE_INTERFACE_DATA _
> ) As Boolean
>
OK.
>
> Zu SetupDiGetDeviceInterfaceDetail habe ich diverse Überladungen. Mal
> die Variante, die deiner Version am nächsten kommt:
>
> Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib
> "setupapi.dll" ( _
> ByVal hDeviceInfoSet As IntPtr, _
> <[In]()> ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
> <[In](), [Out]()> ByRef DeviceInterfaceDetailData As
> SP_DEVICE_INTERFACE_DETAIL_DATA, _
> ByVal DeviceInterfaceDetailDataSize As UInt32, _
> <[Out]()> ByRef RequiredSize As UInt32, _
> <[In](), [Out]()> ByRef DeviceInfoData As SP_DEVINFO_DATA _
> ) As Boolean
>
> Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib
> "setupapi.dll" ( _
> ByVal hDeviceInfoSet As IntPtr, _
> <[In]()> ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
> ByVal DeviceInterfaceDetailData As IntPtr, _
> ByVal DeviceInterfaceDetailDataSize As UInt32, _
> <[Out]()> ByRef RequiredSize As UInt32, _
> <[In](), [Out]()> ByRef DeviceInfoData As SP_DEVINFO_DATA _
> ) As Boolean
>
OK.
> Die zweite Überladung brauchst du für den erstmaligen Aufruf
> zur Ermittlung der Puffergröße, denn dabei musst du IntPtr.Zero
> als dritten Parameter übergeben.
>
Das war bis zu dieser Info schlicht ein unlösbares Probem für mich.
>> Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
>> System.EventArgs) Handles MyBase.Load
>> [...]
>
> Nach den Korrekturen sieht's nun wie folgt aus. Zwar
> liefert SetupDiGetDeviceInterfaceDetail jetzt immer noch false,
> aber nicht mehr mit Marshal.Getlastwin32error = 6 ("ungültiges handle")
> sonder mit Fehler 1784, also "insufficient Buffer". Das ist
> aber auch richtig, denn du hast ja als Länge 0 übergeben
> und bekommst deswegen in "Needed" die benötigte Größe
> zurück.
>Du musst also die Funktion noch einmal mit
> der korrekten Puffergröße aufrufen. Steht ja aber auch
> schon so in deinem eigenen Kommentar. Darüber, dass
> der Funktionswert False ist, kannst du dich also gar
> nicht gewundert haben. ;-)
Jetzt verstehe ich, aber darauf konnte ich wegen zuerst "ungültiges handle"
natürlich nicht kommen.
Nun funktioniert der Code.
Zwei Fragen hätte ich noch dazu,
ich habe sie mit dem Prefix '######## versehen.
'''''''''''''Start Code
' Stand 22.2.2011, 15:55
Imports System.Threading
Imports System.Runtime.InteropServices
Public Class Form1
' ein Relikt, aber vielleicht brauche ich es noch.
' P/Invoke API
'<DllImport("HID.dll")> _
'Private Shared Sub HidD_GetHidGuid(ByRef GuidPtr As Guid)
'End Sub
Public Const BUFFER_SIZE As Short = 1024
Public Const DIGCF_PRESENT As Int32 = (2)
Public Const DIGCF_DEVICEINTERFACE As UInt32 = &H10
Public Const GUID_DEVINTERFACE_DISK As String =
"{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}"
Public Const FORMAT_MESSAGE_FROM_SYSTEM As Int32 = &H1000
<Flags()> _
Public Enum GetClassDevsFlags As UInt32
none = 0
[Default] = 1
Present = 2
AllClasses = 4
Profile = 8
DeviceInterface = 16
End Enum
<StructLayout(LayoutKind.Sequential)> _
Public Structure SP_DEVINFO_DATA
Public cbSize As UInt32
Public interfaceClassGuid As Guid
Public Flags As Int32
Public Reserved As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential, pack:=2)> _
Public Structure SP_DEVICE_INTERFACE_DATA
Public cbSize As UInt32
Public interfaceClassGuid As Guid
Public flags As Int32
Private reserved As UIntPtr
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto, pack:=1)> _
Public Structure SP_DEVICE_INTERFACE_DETAIL_DATA
Public cbSize As UInt32
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=BUFFER_SIZE)> _
Public DevicePath As String
End Structure
Declare Auto Function SetupDiGetClassDevs Lib _
"setupapi.dll" Alias "SetupDiGetClassDevsA" _
(ByVal GuidPtr As IntPtr, _
<[In](), MarshalAs(UnmanagedType.LPTStr)> ByVal EnumPtr As String,
_
ByVal HwndParent As IntPtr, _
ByVal Flags As GetClassDevsFlags) _
As IntPtr
Declare Auto Function SetupDiGetClassDevs Lib _
"setupapi.dll" Alias "SetupDiGetClassDevsA" _
(<[In]()> ByRef GuidPtr As Guid, _
<[In](), MarshalAs(UnmanagedType.LPTStr)> ByVal EnumPtr As String,
_
ByVal HwndParent As IntPtr, _
ByVal Flags As GetClassDevsFlags) _
As IntPtr
Public Declare Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll"
( _
ByVal DeviceInfoSet As IntPtr, _
ByVal DeviceInfoData As IntPtr, _
<[In]()> ByRef InterfaceClassGuid As Guid, _
ByVal MemberIndex As UInt32, _
<[In](), [Out]()> ByRef DeviceInterfaceData As
SP_DEVICE_INTERFACE_DATA) _
As Boolean
Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib _
"setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailW" ( _
ByVal hDevInfo As IntPtr, _
<[In]()> ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
<[In](), [Out]()> ByRef deviceInterfaceDetailData As
SP_DEVICE_INTERFACE_DETAIL_DATA, _
ByVal deviceInterfaceDetailDataSize As UInt32, _
<[Out]()> ByRef requiredSize As UInt32, _
<[In](), [Out]()> ByVal deviceInfoData As SP_DEVINFO_DATA) _
As Boolean
Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib _
"setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailW" ( _
ByVal hDevInfo As IntPtr, _
<[In]()> ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
ByVal deviceInterfaceDetailData As IntPtr, _
ByVal deviceInterfaceDetailDataSize As UInt32, _
<[Out]()> ByRef requiredSize As UInt32, _
<[In](), [Out]()> ByVal deviceInfoData As SP_DEVINFO_DATA) _
As Boolean
Private Declare Function FormatMessage Lib "kernel32" Alias _
"FormatMessageA" ( _
ByVal dwFlags As Int32, _
ByVal lpSource As Int32, _
ByVal dwMessageId As Int32, _
ByVal dwLanguageId As Int32, _
ByVal lpBuffer As String, _
ByVal nSize As Int32, _
ByVal Arguments As Int32) _
As Int32
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim Guid As Guid
Dim spDeviceInterfaceData As New SP_DEVICE_INTERFACE_DATA
Dim spDevInfoData As New SP_DEVINFO_DATA
Dim SPDeviceInterfaceDetailData As New SP_DEVICE_INTERFACE_DETAIL_DATA
Dim LenB As UInt32
Dim Needed As UInt32
Dim DeviceHandle As IntPtr
Dim MemberIndex As UInt32
Dim bRetDiEnum As Boolean
Dim bRetDiEnumInterfaceDetail As Boolean
Dim strAPIDesc As String
Dim strFormat As String
Guid = New Guid(GUID_DEVINTERFACE_DISK)
DeviceHandle = SetupDiGetClassDevs(Guid, Nothing, IntPtr.Zero,
GetClassDevsFlags.Present Or GetClassDevsFlags.DeviceInterface)
strFormat = String.Format("DeviceHandle: {0}", DeviceHandle.ToString)
'lstTrace.Items.Add(strFormat)
Trace.WriteLine(strFormat)
LenB = CUInt(Marshal.SizeOf(spDeviceInterfaceData)) 'LenB = 28
spDeviceInterfaceData.cbSize = LenB
spDevInfoData.cbSize = LenB
' jetzt aus Deinem Vorschlag
'LenB = CUInt(Marshal.SizeOf(SPDeviceInterfaceDetailData)) 'LenB =
514
SPDeviceInterfaceDetailData.cbSize = If(IntPtr.Size = 4, 6UI, 8UI)
MemberIndex = 0UI
bRetDiEnum = SetupDiEnumDeviceInterfaces(DeviceHandle, IntPtr.Zero,
Guid, MemberIndex, spDeviceInterfaceData)
Do While bRetDiEnum
' das ist der erste Aufruf zwecks Ermittlung der Buffergrößen
bRetDiEnumInterfaceDetail = SetupDiGetDeviceInterfaceDetail( _
DeviceHandle, _
spDeviceInterfaceData, _
IntPtr.Zero, 0UI, Needed, _
Nothing)
'spDevInfoData)
' ################# Seltsam ist Folgendes:
' ist der letzte Parameter spDevInfoData, erhalte ich den Fehler
"Falscher Parameter."
' ist der letzte Parameter Nothing, erhalte ich den Fehler "Der an
einen Systemaufruf übergebene Datenbereich ist zu klein."
strFormat = String.Format("Needed: <{0}>", Needed)
'lstTrace.Items.Add(strFormat)
Trace.WriteLine(strFormat)
If Not bRetDiEnumInterfaceDetail Then
strAPIDesc = APIErrorDescription(Err.LastDllError)
strFormat = String.Format(" ***Error 1.
SetupDiGetDeviceInterfaceDetail: {0}, {1}", _
Err.LastDllError.ToString, strAPIDesc)
'lstTrace.Items.Add(strFormat)
Trace.WriteLine(strFormat)
End If
bRetDiEnumInterfaceDetail = SetupDiGetDeviceInterfaceDetail( _
DeviceHandle, _
spDeviceInterfaceData, _
SPDeviceInterfaceDetailData, Needed, Needed, _
Nothing)
'spDevInfoData)
' ############### wie oben:
' ist der letzte Parameter spDevInfoData, erhalte ich den Fehler
"Falscher Parameter."
' ist der letzte Parameter Nothing, erhalte ich gültige Werte denn
bRetDiEnumInterfaceDetail ist endlich True
If Not bRetDiEnumInterfaceDetail Then
strAPIDesc = APIErrorDescription(Err.LastDllError)
strFormat = String.Format(" ***Error 2.
SetupDiGetDeviceInterfaceDetail: {0}, {1}", _
Err.LastDllError.ToString, strAPIDesc)
'lstTrace.Items.Add(strFormat)
Trace.WriteLine(strFormat)
End If
' ###############
' Ich verstehe nicht, wieso der Output nur solange ist wie die
tatsächlichen Daten ohne finale chr(0).
' Schließlich ist SP_DEVICE_INTERFACE_DETAIL_DATA 514 bytes lang.
strFormat = String.Format("SPDeviceInterfaceDetailData.DevicePath:
<{0}>", _
SPDeviceInterfaceDetailData.DevicePath)
'lstTrace.Items.Add(strFormat)
Trace.WriteLine(strFormat)
bRetDiEnum = SetupDiEnumDeviceInterfaces(DeviceHandle, IntPtr.Zero,
Guid, MemberIndex, spDeviceInterfaceData)
MemberIndex += 1UI
Loop
End Sub
' Get Last DLLErr
Public Function APIErrorDescription(ByVal ErrorCode As Int32) As String
Dim strErrDescription As String
Dim lRet As Int32
Dim strFormat As String
APIErrorDescription = ""
strErrDescription = StrDup(255, Chr(0))
Try
lRet = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, _
ErrorCode, 0, strErrDescription, 255, 0)
APIErrorDescription = strErrDescription.Substring(0,
strErrDescription.IndexOf(vbCr))
Catch ex As Exception
strFormat = String.Format(" ***Error
APIErrorDescription({0}: {1}, {2}", _
ErrorCode, Err.Number, Err.Description)
'lstTrace.Items.Add(strFormat)
Trace.WriteLine(strFormat)
APIErrorDescription = "Fehler: Kein Rückgabewert für die Funktion
APIErrorDescription"
End Try
End Function
End Class
'''''''''''''''Ende Code
Das war nun der Anfang.
Es geht ja noch weiter, um den Pfad zu finden, welcher einem bestimmten
USB-Massenspeicher
zugeordnet ist.
Ich werde nach Deinen exzellenten Ausführungen versuchen, die weiteren
API-Definitionen
danach zu verfassen und hoffe fürs erste, ohne Unterstützung zum Erfolg zu
kommen.
Darf ich mich nochmals melden, soferne mich unüberwindliche Hindernisse
am weiteren Fortkommen hindern?
Ich betone, daß ich in diesen paar Tagen mehr im Umgang mit API?s gelernt
habe,
als nach dem Lesen des VB2008-Buches von Klaus Löffelmann.
Bleibt für mich die Frage offen, wie und wo man den Umgang mit API?s
wirklich lernen kann.
Vergleichsweise habe ich mir die C# und C++ Varianten zu diesem Code
angeschaut.
Da bedarf es fast nirgends solch ausgefeilter Techniken und Klimmzüge.
Es ist zwar nicht wirklich einfacher, aber es gibt weniger systemische
Einschränkungen.
Dort lassen sich problemlos Daten, egal ob strukturiert oder nicht, beliebig
irgendwohin übertragen,
Hauptsache die Adresse des ersten Bytes von Quelle und Ziel sind bekannt.
Was sich darinnen befindet, danach frägt das System nicht.
Ist doch so einfach!
Außerdem gibt es gerade in dem Bereich der API-Programmierung in C in den
MS-Dokumentationen Definitionen und Beispiele sonder Zahl. Da blieb Basic
zumeist unberücksichtigt.
Etwas muß ich Dir abschließend noch sagen:
Was mir besondere Freude an Deiner Unterstützung macht, ist Dein Gebrauch
der deutschen Sprache.
Keine Verwechslungen von das und daß, die richtige Verwendung von das Selbe
und das Gleiche,
kein Stammeln und sorgloses Aneinanderreihen von Wörtern,
sondern gut komponierte Sätze mit Subjekt, Prädikat mit einer
übersichtlichen Gliederung der
Sachverhalte obwohl der Gegenstand eher spröde ist.
Mein Kompliment.
Mit den besten Grüßen und einem ganz großen Dankeschön aus Wien
Wolfgang
Ich "liebe" solche Wartezeiten auch sehr!
>> Bei SP_DEVICE_INTERFACE_DETAIL_DATA bin ich anders vorgegangen weil
>> eine Structure mit dynamischer Größe nicht unterstützt wird. Woher
>> hast du die Info, dass die Längebegrenzung BUFFER_SIZE ist?
> 1. aus
> http://stackoverflow.com/questions/2937585/how-to-open-a-serial-port-by-friendly-name
Ah, ok. Ich dachte, du hättest es in der Doku gefunden.
> 2. dachte ich, daß ja diese Definition einmal die Daten einer zuerst
> unbestimmten Länge aufnehmen können muß.
Wobei BUFFER_SIZE ja keine unbestimmte Länge ist. Wie schon kurz
erwähnt bin ich aufgrund der erforderlichen, dynamischen Strukturlänge
anders vorgegangen. Ich verwende den Typ SP_DEVICE_INTERFACE_DETAIL_DATA
gar nicht sondern erzeuge den Puffer mit Marshal.AllocHGlobal.
Da man diverse Funktionen zwei Mal aufrufen muss - beim ersten mal
zur Ermittlung der Puffergröße - habe ich mir dafür jeweils Hilfs-
funktionen geschrieben. Die für SetupDiGetDeviceInterfaceDetail
habe ich hier mal eingefügt. Die ersten beiden Parameter sind In-
Parameter, der dritte Out. Da die Interface-Details nur ein String
sind, ist der Funktionswert auch nur vom Typ String.
Public Shared Function GetDeviceInterfaceDetails( _
ByVal hDevInfoset As IntPtr, _
ByVal DevInterface As SP_DEVICE_INTERFACE_DATA, _
ByRef DevInfo As SP_DEVINFO_DATA) As String
Dim ptrDetails As IntPtr
Dim ReqSize As UInt32
'Determine required buffer size
SetupDiGetDeviceInterfaceDetail(hDevInfoset, DevInterface, IntPtr.Zero, 0, ReqSize, IntPtr.Zero)
If Marshal.GetLastWin32Error <> Win32.Errors.InsufficientBuffer Then
Win32.Helper.ThrowWin32Exception("SetupDiGetDeviceInterfaceDetail")
End If
'alloc buffer
ptrDetails = Marshal.AllocHGlobal(CInt(ReqSize))
Try
DevInfo.Size = Marshal.SizeOf(DevInfo)
Dim size = 4 + If(IntPtr.Size = 4, 2, 4)
Marshal.WriteInt32(ptrDetails, 0, size)
If SetupDiGetDeviceInterfaceDetail( _
hDevInfoset, DevInterface, ptrDetails, ReqSize, ReqSize, DevInfo) Then
Dim ptrString As IntPtr
'advance 4 bytes to start of string buffer
If IntPtr.Size = 4 Then
ptrString = New IntPtr(ptrDetails.ToInt32 + 4)
Else
ptrString = New IntPtr(ptrDetails.ToInt64 + 4)
End If
Return Marshal.PtrToStringAuto(ptrString)
Else
Win32.Helper.ThrowWin32Exception("SetupDiGetDeviceInterfaceDetail")
Return Nothing 'not required, but it avoids the compiler warning about
' the function not returning a value for all code pathes
End If
Finally
Marshal.FreeHGlobal(ptrDetails)
End Try
End Function
>> Und wo steht, dass pack=1 sein muss?
>
> 3. aus Sicherheitsgründen ;-), damit zwischen den Strukturbytes keine
> padding-bytes lagern. War der Gedanke so falsch?
Ich dachte, du hast es vllt irgendwo gelesen. Dann hätte ich das
übernommen. ......Wie ich gerade gefunden habe, sind es wohl
8 Bytes:
http://msdn.microsoft.com/en-us/library/aa383745(VS.85).aspx#controlling_structure_packing
> Nun funktioniert der Code.
> Zwei Fragen hätte ich noch dazu,
> ich habe sie mit dem Prefix '######## versehen.
> Do While bRetDiEnum
> ' das ist der erste Aufruf zwecks Ermittlung der Buffergrößen
> bRetDiEnumInterfaceDetail = SetupDiGetDeviceInterfaceDetail( _
> DeviceHandle, _
> spDeviceInterfaceData, _
> IntPtr.Zero, 0UI, Needed, _
> Nothing)
> 'spDevInfoData)
> ' ################# Seltsam ist Folgendes:
> ' ist der letzte Parameter spDevInfoData, erhalte ich den Fehler
> "Falscher Parameter."
> ' ist der letzte Parameter Nothing, erhalte ich den Fehler "Der an
> einen Systemaufruf übergebene Datenbereich ist zu klein."
Überprüfe noch mal die Deklarationen von SetupDiGetDeviceInterfaceDetail.
Meine sind das jedenfalls nicht. Unter anderem muss der letzte Parameter
ByRef übergeben werden. Ich habe jetzt aber nicht nochmal _alles_ überprüft,
nur ist mir das eben aufgefallen.
> ' ###############
> ' Ich verstehe nicht, wieso der Output nur solange ist wie die
> tatsächlichen Daten ohne finale chr(0).
> ' Schließlich ist SP_DEVICE_INTERFACE_DETAIL_DATA 514 bytes lang.
> strFormat = String.Format("SPDeviceInterfaceDetailData.DevicePath:
> <{0}>", _
> SPDeviceInterfaceDetailData.DevicePath)
Da weiß ich jetzt nicht, was du meinst.
> Darf ich mich nochmals melden, soferne mich unüberwindliche Hindernisse
> am weiteren Fortkommen hindern?
Aber natürlich!
> Außerdem gibt es gerade in dem Bereich der API-Programmierung in C in den
> MS-Dokumentationen Definitionen und Beispiele sonder Zahl. Da blieb Basic
> zumeist unberücksichtigt.
Klar, Basic steht da hinten an. C# eigentlich auch, nur mit der
zusätzlichen Möglichkeit, unsichere ("unsafe") Codeblöcke verwenden
zu können. Gemacht ist die API aber natürlich für die C++ Vertreter.
> Etwas muß ich Dir abschließend noch sagen:
>
> Was mir besondere Freude an Deiner Unterstützung macht, ist Dein Gebrauch
> der deutschen Sprache.
> [...]
I kon scho a schreim wie i sprech, ober i hob's mer halt so ongwöhnt.
;)
Und auch vielen Dank für die Blumen! Darüber freue ich mich natürlich sehr.
--
Armin
>> 2. dachte ich, daß ja diese Definition einmal die Daten einer zuerst
>> unbestimmten Länge aufnehmen können muß.
>
> Wobei BUFFER_SIZE ja keine unbestimmte Länge ist.
Ich habe BUFFER_SIZE auf 1024 gesetzt.
Wenn ich allerdings die von Dir vorgeschlagene Zuweisung
SPDeviceInterfaceDetailData.cbSize = If(IntPtr.Size = 4, 6UI, 8UI)
nicht verwende, sondern die definierte Länge beibehalte geht gar nichts.
Irgendwie verstehe ich das nicht, denn ich dachte, der Bereich DevicePath in
Public Structure SP_DEVICE_INTERFACE_DETAIL_DATA
Public cbSize As UInt32
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=BUFFER_SIZE)> _
Public DevicePath As String
nimmt die Daten auf. Wie geht das bei einer Länge von nur 6UI oder 8UI?
Paßt das der API-Aufruf an?
Es scheint für mich nun so, daß die Daten in
SP_DEVICE_INTERFACE_DETAIL_DATA.DevicePath
nicht in der **angegebenen** Länge sondern in der vom Aufruf erkannten
erforderlichen Länge in DevicePath gespeichert werden.
Über diese internen Vorgänge habe ich sicher ein Informationsdefizit.
Damit erübrigen sich meine Überlegungen weiter
unten zu ev. abschließenden vbNullChar in einem Pufferbereich weiter unten.
Sehr beeindruckend. Das werde ich natürlich noch berücksichtigen.
> Überprüfe noch mal die Deklarationen von SetupDiGetDeviceInterfaceDetail.
> Meine sind das jedenfalls nicht. Unter anderem muss der letzte Parameter
> ByRef übergeben werden. Ich habe jetzt aber nicht nochmal _alles_
> überprüft,
> nur ist mir das eben aufgefallen.
Die Definition des letzten Parameters habe ich auf ByRef geändert,
aber das Ergebnis ist im ersten Aufruf "Falscher Parameter" beim zweiten
"Der angegebene Benutzerpuffer ist für den angeforderten Vorgang nicht
zuzlässig."
Es geht bei mir nur mit der Definition des letzten Parameters mit ByVal und
mit "Nothing" im letzen Parameter des Aufrufs
SetupDiGetDeviceInterfaceDetail
Aber ich werde selbstverständlich Deinen Code einbauen und berichten.>
>
>> ' ###############
>> ' Ich verstehe nicht, wieso der Output nur solange ist wie die
>> tatsächlichen Daten ohne finale chr(0).
>> ' Schließlich ist SP_DEVICE_INTERFACE_DETAIL_DATA 514 bytes
>> lang.
>> strFormat =
>> String.Format("SPDeviceInterfaceDetailData.DevicePath:
>> <{0}>", _
>> SPDeviceInterfaceDetailData.DevicePath)
>
> Da weiß ich jetzt nicht, was du meinst.
Es werden doch üblicherweise Puffer bei API-Aufrufen nach den eigentlichen
Daten mit vbNullChar aufgefüllt.
Also müßten diese doch als kleine Quadrate angezeigt werden, wenn sie nicht
vorher entfernt werden.
Doch in diesem Fall ist das anscheinend nicht so.
>> Darf ich mich nochmals melden, soferne mich unüberwindliche Hindernisse
>> am weiteren Fortkommen hindern?
>
> Aber natürlich!
Danke!
>> Was mir besondere Freude an Deiner Unterstützung macht, ist Dein Gebrauch
>> der deutschen Sprache.
>> [...]
>
> I kon scho a schreim wie i sprech, ober i hob's mer halt so ongwöhnt.
> ;)
Eh klor, i a.
Wolfgang
>>> 2. dachte ich, daß ja diese Definition einmal die Daten einer zuerst
>>> unbestimmten Länge aufnehmen können muß.
>>
>> Wobei BUFFER_SIZE ja keine unbestimmte Länge ist.
> Ich habe BUFFER_SIZE auf 1024 gesetzt.
> Wenn ich allerdings die von Dir vorgeschlagene Zuweisung
> SPDeviceInterfaceDetailData.cbSize = If(IntPtr.Size = 4, 6UI, 8UI)
> nicht verwende, sondern die definierte Länge beibehalte geht gar nichts.
>
> Irgendwie verstehe ich das nicht, denn ich dachte, der Bereich DevicePath in
> Public Structure SP_DEVICE_INTERFACE_DETAIL_DATA
> Public cbSize As UInt32
> <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=BUFFER_SIZE)> _
> Public DevicePath As String
> nimmt die Daten auf. Wie geht das bei einer Länge von nur 6UI oder 8UI?
> Paßt das der API-Aufruf an?
Lt Doku zu SetupDiGetDeviceInterfaceDetail:
"The cbSize member always contains the size of the *fixed* part of
the data structure, not a size reflecting the variable-length string
at the end."
Mit dem "fixed part" ist eben sizeof(struct) gemeint, und das eben
6 bzw 8 Bytes.
> Es scheint für mich nun so, daß die Daten in
> SP_DEVICE_INTERFACE_DETAIL_DATA.DevicePath
> nicht in der **angegebenen** Länge sondern in der vom Aufruf erkannten
> erforderlichen Länge in DevicePath gespeichert werden.
> Über diese internen Vorgänge habe ich sicher ein Informationsdefizit.
> Damit erübrigen sich meine Überlegungen weiter
> unten zu ev. abschließenden vbNullChar in einem Pufferbereich weiter unten.
- Im verwalteten Code besteht die Struktur aus cbSize und der Referenz
auf den String (da String=Referenztyp). Der String liegt irgendwo
im Heap aber nicht direkt in der Struktur. Soweit dürfte es klar sein.
- Beim API-Aufruf wird vom Marshaller zuerst die nicht-verwaltete Struktur
angelegt. DevicePath bekommt die Größe BUFFER_SIZE Zeichen. Dann wird die
verwaltete in die nicht-verwaltete Struktur kopiert, wobei der String mit
nul-Terminator abgeschlossen wird (weil ByValTStr). Ob der restliche
Puffer mit nul aufgefüllt wird, weiß ich nicht; das ist aber auch irrelevant.
Die API-Funktion erwartet in cbSize die davon abweichende Länge wie oben
zitiert (6 oder 8).
- Zwischen Verlassen der API-Funktion und Rückkehr zum verwalteten Code
wird der Marshaller wieder aktiv weil das Out-Attribut auf den Parameter
angewandet wurde. Es werden also die Daten ins verwaltete Objekt zurück-
kopiert. Da Strings als "immutable" gelten, muss der Marshaller einen
_neuen_ String anlegen bevor er die Daten bis zum nul-Terminator kopiert.
Was nach dem ersten nul kommt, ist deswegen irrelevant.
Das lässt sich einfach testen:
Dim details As SP_DEVICE_INTERFACE_DETAIL_DATA
details.Size = 8
details.DevicePath = "abc"
Dim olddevicepath = details.DevicePath
SetupDiGetDeviceInterfaceDetail( _
hDevInfoset, DevInterface, details, 256, ReqSize, DevInfo)
MsgBox(olddevicepath Is details.DevicePath)
Die MsgBox gibt "False" aus, d.h. es handelt sich nach dem Aufruf um
einen anderen String (oder genauer: um eine andere Instanz).
>>
>>> ' ###############
>>> ' Ich verstehe nicht, wieso der Output nur solange ist wie die
>>> tatsächlichen Daten ohne finale chr(0).
>>> ' Schließlich ist SP_DEVICE_INTERFACE_DETAIL_DATA 514 bytes
>>> lang.
>>> strFormat =
>>> String.Format("SPDeviceInterfaceDetailData.DevicePath:
>>> <{0}>", _
>>> SPDeviceInterfaceDetailData.DevicePath)
>>
>> Da weiß ich jetzt nicht, was du meinst.
>
> Es werden doch üblicherweise Puffer bei API-Aufrufen nach den eigentlichen
> Daten mit vbNullChar aufgefüllt.
> Also müßten diese doch als kleine Quadrate angezeigt werden, wenn sie nicht
> vorher entfernt werden.
> Doch in diesem Fall ist das anscheinend nicht so.
s.o.
--
Armin
>
> Public Shared Function GetDeviceInterfaceDetails( _
> ByVal hDevInfoset As IntPtr, _
> ByVal DevInterface As SP_DEVICE_INTERFACE_DATA, _
> ByRef DevInfo As SP_DEVINFO_DATA) As String
>
> Dim ptrDetails As IntPtr
> Dim ReqSize As UInt32
>
> 'Determine required buffer size
> SetupDiGetDeviceInterfaceDetail(hDevInfoset, DevInterface,
> IntPtr.Zero, 0, ReqSize, IntPtr.Zero)
>
> If Marshal.GetLastWin32Error <> Win32.Errors.InsufficientBuffer
> Then
Fehler Win32 wurde nicht deklariert.
Wie kriege ich diesen Fehler weg?
In der lokalen Hilfe habe ich nichts zu Win32 gefunden.
Wahrscheinlich suche ich aber falsch.
Du hast es schon schwer mit mir, es tut mir so leid.
Kaum baue ich etwas nach Deinem Vorschlag ein tauchen sofort die nächsten
Probeme auf.
Es handelt sich bei Win32.Errors.InsufficientBuffer doch um einen
Fehlercode.
Welchen Namespace muß ich importieren und brauche ich einen zusätzlichen
Verweis?
>
> Win32.Helper.ThrowWin32Exception("SetupDiGetDeviceInterfaceDetail")
Leider wie oben.
> Try
> DevInfo.Size = Marshal.SizeOf(DevInfo)
Nachdem in meinem Code alle Längen als Uint32 definiert sind
habe ich CUInt (Marshal.SizeOf(DevInfo)) davor gesetzt.
Ich bedanke mich wieder im Voraus für Deine Unterstützung,
Wolfgang
Verstanden.
Jetzt ist mir auch das verständlich.
Vielen Dank
Wolfgang
Oh ja, Verzeihung, mein Fehler. Ich habe nicht alles Relevante
aus dem Projekt gepostet. Hier der Auszug:
Imports System.Runtime.InteropServices
Namespace Win32
Public Enum Errors As UInteger
PathNotFound = 3
NoMoreFiles = 18
NotReady = 21
NoMoreItems = 259
InsufficientBuffer = 122
InvalidUserBuffer = 1784
End Enum
Public Class Helper
Public Shared Sub ThrowWin32Exception(ByVal Location As String)
ThrowWin32Exception(Marshal.GetLastWin32Error, Location)
End Sub
Public Shared Sub ThrowWin32Exception(ByVal [error] As Integer, ByVal Location As String)
Throw New ComponentModel.Win32Exception([error], "Error at " & Location)
End Sub
End Class
End Namespace
--
Armin
Auf der Site
http://thedailyreviewer.com/dotnet/view/aquire-path-of-usb-device-101723333
hat jemand ohne Erfolg mittels VB6 über die API CreateFile
die Seriennummer eines USB-Masenspeichers zu ermitteln versucht und blieb
dort ohne Antwort auf seine Frage .
Kann der Aufruf CreateFile überhaupt funktionieren wenn
'SPDeviceInterfaceDetailData.DevicePath auf
\\?\usbstor#disk&ven_sandisk&prod_cruzer_contour&rev_4.13#000016830775486a&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}lautet? Denn erbringt in FileHandle immer -1.Ich denke dieser Ansatz ist erfolglos. FileHandle = CreateFile(SPDeviceInterfaceDetailData.DevicePath, _ GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, _ Security, _ OPEN_EXISTING, 0, IntPtr.Zero)Wenn das so nicht geht, werde ich zuerst eine Nachdenkphase für micheinläuten.Allerdings steht in SPDeviceInterfaceDetailData.DevicePath die Seiennummerdrin:#000016830775486a&0# (das sind exakt die Daten zwischen den Rautezeichen).Eventuell kommt man damit weiter.Vielleicht gehts mitbRetDiEnumHidD_GetAttributes = HidD_GetAttributes(DeviceHandle,DeviceAttributes) ?Beim Testen erhielt ich zwar immer bRetDiEnumHidD_GetAttributes = False.Möglicherweise ergibt dieser Aufruf aber wegen falscher Definitionen nichts. <StructLayout(LayoutKind.Sequential, pack:=2)> _ Public Structure HIDD_ATTRIBUTES Public Size As UInt32 Public VendorID As Int16 Public ProductID As Int16 Public VersionNumber As Int16 End Structure Declare Function HidD_GetAttributes Lib "HID.dll" _ (ByVal Handle As IntPtr, _ ByRef Attributes As HIDD_ATTRIBUTES) _ As BooleanEigentlich stehen die mit Deiner massiven Unterstützung ermitteltenInformationen so auch in der Registry.Soweit war ich ohne die API-Aufrufe auch schon.Es läuft jetzt wie von Dir anfangs schon vermutet daruaf hinaus, denZusammenhang von VID, PID, Seriennummerzum MountedPoint herzustellen.Ich werde ausgiebig über Deinen Vorschlag aus dem Posting vom 17.02.201118:16nachdenken. Vielleicht geht eine Glühbirne an.Danke,Wolfgang
Ich versuche es nochmals,
Wolfgang
Auf der Site
http://thedailyreviewer.com/dotnet/view/aquire-path-of-usb-device-101723333
hat jemand ohne Erfolg mittels VB6 über die API CreateFile
die Seriennummer eines USB-Masenspeichers zu ermitteln versucht und blieb
dort ohne Antwort auf seine Frage.
Kann der Aufruf CreateFile überhaupt funktionieren wenn
'SPDeviceInterfaceDetailData.DevicePath auf
\\?\usbstor#disk&ven_sandisk&prod_cruzer_contour&rev_4.13#000016830775486a&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}lautet
?
Denn erbringt in FileHandle immer -1.
Ich denke dieser Ansatz ist erfolglos.
FileHandle = CreateFile(SPDeviceInterfaceDetailData.DevicePath, _
GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, _
Security, _
OPEN_EXISTING, 0, IntPtr.Zero)
Wenn das so nicht geht, werde ich zuerst eine Nachdenkphase für mich
einläuten.
Allerdings steht in SPDeviceInterfaceDetailData.DevicePath die
Seiennummerdrin:#000016830775486a&0#
(das sind exakt die Daten zwischen den Rautezeichen).
Eventuell kommt man damit weiter.
Vielleicht gehts möglicherweise mit
bRetDiEnumHidD_GetAttributes =
HidD_GetAttributes(DeviceHandle,DeviceAttributes) ?
Beim Testen erhielt ich zwar immer bRetDiEnumHidD_GetAttributes = False.
Möglicherweise ergibt dieser Aufruf aber wegen falscher Definitionen
nichts.
<StructLayout(LayoutKind.Sequential, pack:=2)> _
Public Structure HIDD_ATTRIBUTES
Public Size As UInt32
Public VendorID As Int16
Public ProductID As Int16
Public VersionNumber As Int16
End Structure
Declare Function HidD_GetAttributes Lib "HID.dll" _
(ByVal Handle As IntPtr, _
ByRef Attributes As HIDD_ATTRIBUTES) _
As Boolean
Eigentlich stehen die mit Deiner massiven Unterstützung ermittelten
Informationen so auch in der Registry.
Soweit war ich ohne die API-Aufrufe auch schon.
Es läuft vermutlich wie von Dir anfangs schon vermutet darauf hinaus, den
Dies habe ich eingebaut.
Aber ich wage es schon fast nicht mehr Dich noch weiter zu belästigen.
Beim Aufruf der Funktion
Public Shared Function GetDeviceInterfaceDetails( _
ByVal hDevInfoset As IntPtr, _
ByVal DevInterface As SP_DEVICE_INTERFACE_DATA, _
ByRef DevInfo As SP_DEVINFO_DATA) As String
in der Form
strDevicePath = GetDeviceInterfaceDetails(DeviceHandle,
spDeviceInterfaceData, spDevInfoData)
passiert Folgendes bei:
If Marshal.GetLastWin32Error <> Win32.Errors.InsufficientBuffer Then
Win32.Helper.ThrowWin32Exception("SetupDiGetDeviceInterfaceDetail")
End If
der Marshal.GetLastWin32Error = 87, ERROR_INVALID_PARAMETER
Nun kommt der Namespace ins Spiel.
In dem Sub
Public Shared Sub ThrowWin32Exception(ByVal [error] As Integer, ByVal
Location As String)
im Stmt
Throw New ComponentModel.Win32Exception([error], "Error at " &
Location)
kommt es zu einer Win32Exception wurde nicht behandelt.
Und hier ist Schluß.
Es kommt also zum selben Fehlercode wie beim nunmehr auskommentierten Aufruf
' das ist der erste Aufruf zwecks Ermittlung der Buffergrößen
bRetDiEnumInterfaceDetail = SetupDiGetDeviceInterfaceDetail( _
DeviceHandle, _
spDeviceInterfaceData, _
IntPtr.Zero, 0UI, Needed, _
spDevInfoData)
Ich bin schon ziemlich verzagt und weiß mir keinen Rat mehr.
Es muß an der Definition von
<StructLayout(LayoutKind.Sequential)> _
Public Structure SP_DEVINFO_DATA
Public cbSize As UInt32
Public interfaceClassGuid As Guid
Public Flags As Int32
Public Reserved As IntPtr
End Structure
und
Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib _
"setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailW" ( _
ByVal hDevInfo As IntPtr, _
<[In]()> ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
<[In](), [Out]()> ByRef deviceInterfaceDetailData As
SP_DEVICE_INTERFACE_DETAIL_DATA, _
ByVal deviceInterfaceDetailDataSize As UInt32, _
<[Out]()> ByRef requiredSize As UInt32, _
<[In](), [Out]()> ByRef deviceInfoData As SP_DEVINFO_DATA) _
As Boolean
liegen.
Wobei es egal ist ob es
<[In](), [Out]()> ByRef deviceInfoData As SP_DEVINFO_DATA) _
oder
<[In](), [Out]()> ByVal deviceInfoData As SP_DEVINFO_DATA) _
lautet.
Vielleicht hast Du noch bessere Nerven als ich.
Mit bestem Dank
Wolfgang
Also bei mir funktioniert's. Deklaration:
Public Declare Auto Function CreateFile Lib "kernel32.dll" ( _
<MarshalAs(UnmanagedType.LPTStr)> ByVal lpFileName As String, _
ByVal DesiredAccess As UInt32, _
ByVal ShareMode As UInt32, _
ByVal SecurityAttributes As IntPtr, _
ByVal CreationDisposition As UInt32, _
ByVal FlagsAndAttributes As UInt32, _
ByVal hTemplateFile As IntPtr) _
As Microsoft.Win32.SafeHandles.SafeFileHandle
Aufruf:
CreateFile(Details, GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, _
IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero)
Weil SecurityAttributes muss ich keine übergeben.
> Vielleicht gehts möglicherweise mit
> bRetDiEnumHidD_GetAttributes =
> HidD_GetAttributes(DeviceHandle,DeviceAttributes) ?
> Beim Testen erhielt ich zwar immer bRetDiEnumHidD_GetAttributes = False.
>
> Möglicherweise ergibt dieser Aufruf aber wegen falscher Definitionen
> nichts.
> <StructLayout(LayoutKind.Sequential, pack:=2)> _
> Public Structure HIDD_ATTRIBUTES
> Public Size As UInt32
> Public VendorID As Int16
> Public ProductID As Int16
> Public VersionNumber As Int16
> End Structure
Lasse doch mal das "pack" weg.
> Declare Function HidD_GetAttributes Lib "HID.dll" _
> (ByVal Handle As IntPtr, _
> ByRef Attributes As HIDD_ATTRIBUTES) _
> As Boolean
Scheint zu passen. Ich würde noch <[in], Out> vor den zweiten Parameter setzen.
Attributes.Size wirst du vor dem Aufruf schon besetzen denke ich.
> Es läuft vermutlich wie von Dir anfangs schon vermutet darauf hinaus, den
> Zusammenhang von VID, PID, Seriennummerzum MountedPoint herzustellen.
Yep. In diese Richtung hatte ich nicht mehr weitergeforscht
weil ich dann auch ne Auszeit brauchte. War dann dazu übergegangen,
die ganzen "device properties" zu enumerieren.
Ich habe bisher immer noch nicht herausgefunden, wie man die Disk-Numbers
bei "\\.\PhysicalDriveXY" herausfindet. Ich meine: Die Lösung zu deinem
eigentlich Problem wäre eigentlich ganz einfach: Wenn du mit
FindFirstFolume/FindNextVolume die Volumes enumerierst, hast du
im Ergebnis die Disk-Nummern stehen, auf denen sich das Volume befindet.
Wenn du jetzt noch wüsstest, dass
Disk 0 = Platte 1
Disk 1 = Platte 2
Disk 2 = USB-Stick
dann wärst du eigentlich schon am Ziel. Nur, mir fehlt eben eine
verlässliche Quelle dazu, wie man an die Liste der Disks kommt.
Denn, wie schon einmal geschrieben, die Aufzählung der Devices mit
SetupClassID = Disk gibt *nicht* die Liste zurück, aus der man
die Disk-Nummern herausziehen könnte.
--
Armin
>
> Dies habe ich eingebaut.
>
> Aber ich wage es schon fast nicht mehr Dich noch weiter zu belästigen.
Du belästigst mich nicht. Alles Freiwillige hier (einige werden
sicher noch mitlesen). Wenn ich keine Böcke oder Zeit mehr habe,
dann sag ich das schon oder es dauert eben länger.
> passiert Folgendes bei:
> If Marshal.GetLastWin32Error <> Win32.Errors.InsufficientBuffer Then
> Win32.Helper.ThrowWin32Exception("SetupDiGetDeviceInterfaceDetail")
> End If
> der Marshal.GetLastWin32Error = 87, ERROR_INVALID_PARAMETER
> [...]
> <StructLayout(LayoutKind.Sequential)> _
> Public Structure SP_DEVINFO_DATA
> Public cbSize As UInt32
> Public interfaceClassGuid As Guid
> Public Flags As Int32
> Public Reserved As IntPtr
> End Structure
passt
> Public Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib _
> "setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailW" ( _
> ByVal hDevInfo As IntPtr, _
> <[In]()> ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
> <[In](), [Out]()> ByRef deviceInterfaceDetailData As
> SP_DEVICE_INTERFACE_DETAIL_DATA, _
> ByVal deviceInterfaceDetailDataSize As UInt32, _
> <[Out]()> ByRef requiredSize As UInt32, _
> <[In](), [Out]()> ByRef deviceInfoData As SP_DEVINFO_DATA) _
> As Boolean
Ist schon wieder nicht meine Deklaration! :-) Meine beiden
Überladungen, die in der Hilfsfunktion "GetDeviceInterfaceDetails"
genutzt werden, haben einen IntPtr als dritten Parameter.
Gehe mit dem Cursor innerhalb der Hilfs-Funktion "GetDeviceInterfaceDetails"
auf die beiden Aufrufe von SetupDiGetDeviceInterfaceDetail und
führe dann jeweils "Gehe zu Definition" aus (Kontextmenü oder Shortcut
(bei mir Shift+F2)). Die jeweiligen Deklarationen bitte nochmal posten.
Müsstest du von mir aber schon haben.
> Wobei es egal ist ob es
> <[In](), [Out]()> ByRef deviceInfoData As SP_DEVINFO_DATA) _
> oder
> <[In](), [Out]()> ByVal deviceInfoData As SP_DEVINFO_DATA) _
>
> lautet.
Wenn der Typ SP_DEVINFO_DATA ist, dann _muss_ es ByRef sein.
Auf dem Stack wird immer ein Pointer erwartet. Der kann NULL oder
sonstwas sein. Wenn in der Deklaration ByRef SP_DEVINFO_DATA
steht, dann wird _immer_ ein Zeiger _ungleich_ NULL übergeben.
Selbst wenn du "Nothing" übergibst, ist das ein Zeiger auf
ein Objekt. Der "Trick" ist, dass "Nothing" bei Wertetypen
den Standardwert bedeutet. Es wird also _kein_ NULL-Pointer
sondern ein Pointer auf eine Objekt übergeben, das mit
Standardwerten belegt ist.
Damit man bei Wertetypen NULL übergeben kann, muss
eine Überladung mit dem Typ ByVal IntPtr geschrieben
und IntPtr.Zero übergeben werden. Eine andere Syntax
ist mir in VB.Net nicht bekannt.
Nur, falls das nicht schon klar gewesen sein sollte. :-)
--
Armin
Selbst bei der Definition der Konstanten
Public Const GENERIC_READ As UInt32 = &H8000000
hatte ich das Problem, daß UInt32 natürlich keine vorzeichenbehaftete
Hexzahl annimmt.
Ich habe deshalb sowohl im Declare CreateFile
als auch für die Konstante UInt32 auf Long umgeändert.
Der Fehler war zwar weg, aber das negative Ergebnis nicht: Der (das?) Handle
ist weiter invalid.
Irgendwie schaffe ich das **ganze** nicht.
Ich wage jetzt den schüchternen Versuch, Dir zwei Varianten vorzuschlagen,
die wahrscheinlich viele Fragen erübrigen:
1. daß ich Dir meine Variante des Projekts zusende (das wage ich nicht
wirklich, denn ich kann Dich schlecht zu einer Fehlersuche meiner Variante
einladen) oder
2. Du sendest mir Deine funktionierende Lösung (inkl. dem CreateFile), egal
in welchem Teststadium sie sich befindet.
Bei der zweiten Variante kann ich mir sehr gut vorstellen,
daß ich sie ausführlich studieren könnte, um
alle Deine Ansätze in meinen bislang gescheiterten Versuch einzubauen.
Wenn mein Projekt funktionieren sollte, sende es ich Dir freudig zu und
poste es auch gerne in diesem Forum.
Entschuldige meine Kühnheit, aber etwas Besseres fällt mir zu meiner
Unfähigkeit nicht mehr ein. :-((
Danke,
Wolfgang
ByVal deviceInterfaceDetailData As IntPtr, _
ByVal deviceInterfaceDetailDataSize As UInt32, _
<[Out]()> ByRef requiredSize As UInt32, _
<[In](), [Out]()> ByRef deviceInfoData As IntPtr) _
As Boolean
>
>> Wobei es egal ist ob es
>> <[In](), [Out]()> ByRef deviceInfoData As SP_DEVINFO_DATA) _
>> oder
>> <[In](), [Out]()> ByVal deviceInfoData As SP_DEVINFO_DATA) _
>>
>> lautet.
>
> Wenn der Typ SP_DEVINFO_DATA ist, dann _muss_ es ByRef sein.
Aber der Fehler "Parameter falsch" kommt trotzdem.
Ich verstehe es nicht.
> Auf dem Stack wird immer ein Pointer erwartet. Der kann NULL oder
> sonstwas sein. Wenn in der Deklaration ByRef SP_DEVINFO_DATA
> steht, dann wird _immer_ ein Zeiger _ungleich_ NULL übergeben.
> Selbst wenn du "Nothing" übergibst, ist das ein Zeiger auf
> ein Objekt. Der "Trick" ist, dass "Nothing" bei Wertetypen
> den Standardwert bedeutet. Es wird also _kein_ NULL-Pointer
> sondern ein Pointer auf eine Objekt übergeben, das mit
> Standardwerten belegt ist.
>
> Damit man bei Wertetypen NULL übergeben kann, muss
> eine Überladung mit dem Typ ByVal IntPtr geschrieben
> und IntPtr.Zero übergeben werden. Eine andere Syntax
> ist mir in VB.Net nicht bekannt.
>
> Nur, falls das nicht schon klar gewesen sein sollte. :-)
Oh ja, hat Löffelmann in seinem Buch ausführlich beschrieben.
Wolfgang
Wenn ich den Namespace Win32 vor der Public Class Form1 aufnehme,
(warscheinlich ist dies der falsche Platz, oder doch nicht),
der Code für Public Shared Function GetDeviceInterfaceDetails ist noch
auskommentiert, so
bringt das Declare für CreateFile den Fehler,
Win32.SafeHandles.SafeFileHandle ist nicht definiert.
Vor dem Einfügen war Win32.SafeHandles.SafeFileHandle noch vorhanden.
Hmmm!
Wolfgang
"Armin Zingler" <az.n...@freenet.de> wrote in message
news:8sib0n...@mid.uni-berlin.de...
> Überprüfe noch mal die Deklarationen von SetupDiGetDeviceInterfaceDetail.
> Meine sind das jedenfalls nicht.
> Unter anderem muss der letzte Parameter
> ByRef übergeben werden. Ich habe jetzt aber nicht nochmal _alles_
> überprüft,
> nur ist mir das eben aufgefallen.
Das ist ja das Problem:
ändere ich diesen letzten Parameter auf ByRef erhalte ich beim Aufruf Deiner
Funktion
den Fehler "Parameter falsch"
Nun weiß ich nicht, wo ich ansetzen soll.
Wolfgang
Stecke den Code in eine eigene Datei.
--
Armin
Public Const GENERIC_READ As UInt32 = &H8000000UI
UInteger Literal mit "UI" Suffix.
> Ich habe deshalb sowohl im Declare CreateFile
> als auch für die Konstante UInt32 auf Long umgeändert.
Ist falsch. Long=Int64
> 1. daß ich Dir meine Variante des Projekts zusende (das wage ich nicht
> wirklich, denn ich kann Dich schlecht zu einer Fehlersuche meiner Variante
> einladen) oder
Schicke das Projekt gezippt bitte an
az punkt no unterstrich spam at freenet punkt de
Also wie meine Absender-Adresse hier im Posting, ergänzt um
einen Unterstrich zwischen "no" und "spam"
--
Armin
Die Definition von Create File lautet nach Deinem Vorschlag
Public Declare Auto Function CreateFile Lib "kernel32.dll" ( _
<MarshalAs(UnmanagedType.LPTStr)> ByVal lpFileName As String, _
ByVal DesiredAccess As UInt32, _
ByVal ShareMode As UInt32, _
ByVal SecurityAttributes As IntPtr, _
ByVal CreationDisposition As UInt32, _
ByVal FlagsAndAttributes As UInt32, _
ByVal hTemplateFile As IntPtr) _
As Win32.SafeHandles.SafeFileHandle
Und nachdem ich anschließend noch die Attribute brauche:
<StructLayout(LayoutKind.Sequential)> _
Public Structure HIDD_ATTRIBUTES
Public Size As UInt32
Public VendorID As Int16
Public ProductID As Int16
Public VersionNumber As Int16
End Structure
Declare Function HidD_GetAttributes Lib "HID.dll" _
(ByVal Handle As IntPtr, _
<[In](), [Out]()> ByRef Attributes As HIDD_ATTRIBUTES) _
As Boolean
Der Aufruf lautet:
FileHandle = CreateFile(SPDeviceInterfaceDetailData.DevicePath.Substring(4),
_
GENERIC_READ, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, _
IntPtr.Zero, _
OPEN_EXISTING, 0, IntPtr.Zero)
FileHandle.IsInvalid.ToString ist True.
Dann habe ich probiert, die 1. 4 Bytes wegzulassen, also
usbstor#disk&ven_sandisk&prod_cruzer_contour&rev_4.13#000016830775486a&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
Wieder True.
Dann dachte ich den wahrscheinlich Unicode-String ins ASCII Format zu
übertragen.
Wieder True.
Dann versuchte ich noch das Fragezeichen in \\?\ durch einen Punkt zu
tauschen und die
Varianten as it is und ins ASCII-Format übersetzt.
Wieder True.
Ich kriege ganz einfach keinen gültigen FileHandle mit CreateFile.
Was könnte ich noch versuchen?
Danke,
Wolfgang
Die Deklarationen scheinen zu stimmen.
In jedem Falle wird "\\?\" benötigt.
> Dann dachte ich den wahrscheinlich Unicode-String ins ASCII Format zu
> übertragen.
Wie das?
> Wieder True.
> Dann versuchte ich noch das Fragezeichen in \\?\ durch einen Punkt zu
> tauschen und die
> Varianten as it is und ins ASCII-Format übersetzt.
> Wieder True.
>
> Ich kriege ganz einfach keinen gültigen FileHandle mit CreateFile.
>
> Was könnte ich noch versuchen?
Mit genau dem Code, den ich dir geschickt habe, funktioniert es hier
bei mir. Was liefert denn Marhal.GetLastwin32Error als Fehler zurück?
--
Armin
5, Zugriff verweigert.
Danke, das war ein heißer Tip.
Ich entwickle und erledige auch alle übrigen Aufgaben grundsätzklich als
eingeschränkter User.
Wenn ich das Programm als Admin starte erhalte ich wirklich
"FileHandle.Invalid = False"
Kannst Du mir weiterhelfen, daß das Programm auch als
eingeschränkter User funktioniert?
Wäre höchst wünschenswert.
Danke,
Wolfgang
Das kann nur der Administrator ändern. An welcher Schraube
da zu drehen wäre, kann ich dir aber leider nicht beantworten.
Evtl kannst du auch über den Parameter lpSecurityAttributes
etwas erreichen. Dabei kann ich dir aber leider auch nicht
weiterhelfen (außer selbst nachzulesen).
--
Armin
Hmmm... und wer ist das? ;-))
> An welcher Schraube
> da zu drehen wäre, kann ich dir aber leider nicht beantworten.
>
> Evtl kannst du auch über den Parameter lpSecurityAttributes
> etwas erreichen. Dabei kann ich dir aber leider auch nicht
> weiterhelfen (außer selbst nachzulesen).
Werde ich sicher tun.
Danke,
Wolfgang
> Evtl kannst du auch über den Parameter lpSecurityAttributes
> etwas erreichen. Dabei kann ich dir aber leider auch nicht
> weiterhelfen (außer selbst nachzulesen).
Also wenn ich mich auf die Security Attributes einlasse
komme ich vom Hundertsten in Tausendste.
Um das Konzept der SACL?s und DACL?s zu verstehen und sich darin
einzuarbeiten bedarf es
sicher längere Zeit.
Ich habe einmal versuchsweise mit einem gefundenen VBS-Skript die
Informationen für nur
einen Verzeichnis ermittelt, und bin dabei schwindlich geworden:
***************
Programm F:\Daten\VBS\Berechtigungen_Auslesen.vbs, 3/2/2011 6:59:55 AM
Auswertung der Berechtigungen zum Verzeichnis
F:\Daten\VB90\HidD_GetHidGuid\HidD_GetHidGuid\bin\Debug
Win32_LogicalFileSecuritySettings
=================================
Caption: Security settings of
F:\Daten\VB90\HidD_GetHidGuid\HidD_GetHidGuid\bin\Debug
ControlFlags: 32772
Description: Security settings of
F:\Daten\VB90\HidD_GetHidGuid\HidD_GetHidGuid\bin\Debug
OwnerPermissions: True
Path: F:\Daten\VB90\HidD_GetHidGuid\HidD_GetHidGuid\bin\Debug
SettingID:
Win32_SecurityDescriptor
------------------------
Owner Name: WB Internet
Owner SIDString: S-1-5-21-842925246-1715567821-725345543-1004
Owner Domain: WB_ASUS
ControlFlags.....SE_DACL_PRESENT
SE_SELF_RELATIVE
DACL (discretionary access control list) Contents [Win32_ACE objects]
---------------------------------
1. Trustee Name: Administrators
Trustee Domain: BUILTIN
Trustee SIDString: S-1-5-32-544
Ace (Access control entry) Type: Access Allowed
AccessMask.........FILE_LIST_DIRECTORY
FILE_ADD_FILE
FILE_ADD_SUBDIRECTORY
FILE_READ_EA
FILE_WRITE_EA
FILE_TRAVERSE
FILE_DELETE_CHILD
FILE_READ_ATTRIBUTES
FILE_WRITE_ATTRIBUTES
DELETE
READ_CONTROL
WRITE_DAC
WRITE_OWNER
SYNCHRONIZE
AceFlags...........OBJECT_INHERIT_ACE
CONTAINER_INHERIT_ACE
2. Trustee Name: SYSTEM
Trustee Domain: NT AUTHORITY
Trustee SIDString: S-1-5-18
Ace (Access control entry) Type: Access Allowed
AccessMask.........FILE_LIST_DIRECTORY
FILE_ADD_FILE
FILE_ADD_SUBDIRECTORY
FILE_READ_EA
FILE_WRITE_EA
FILE_TRAVERSE
FILE_DELETE_CHILD
FILE_READ_ATTRIBUTES
FILE_WRITE_ATTRIBUTES
DELETE
READ_CONTROL
WRITE_DAC
WRITE_OWNER
SYNCHRONIZE
AceFlags...........OBJECT_INHERIT_ACE
CONTAINER_INHERIT_ACE
3. Trustee Name: WB Internet
Trustee Domain: WB_ASUS
Trustee SIDString: S-1-5-21-842925246-1715567821-725345543-1004
Ace (Access control entry) Type: Access Allowed
AccessMask.........FILE_LIST_DIRECTORY
FILE_ADD_FILE
FILE_ADD_SUBDIRECTORY
FILE_READ_EA
FILE_WRITE_EA
FILE_TRAVERSE
FILE_DELETE_CHILD
FILE_READ_ATTRIBUTES
FILE_WRITE_ATTRIBUTES
DELETE
READ_CONTROL
WRITE_DAC
WRITE_OWNER
SYNCHRONIZE
4. Trustee Name: CREATOR OWNER
Trustee Domain:
Trustee SIDString: S-1-3-0
Ace (Access control entry) Type: Access Allowed
AceFlags...........OBJECT_INHERIT_ACE
CONTAINER_INHERIT_ACE
INHERIT_ONLY_ACE
5. Trustee Name: Users
Trustee Domain: BUILTIN
Trustee SIDString: S-1-5-32-545
Ace (Access control entry) Type: Access Allowed
AccessMask.........FILE_LIST_DIRECTORY
FILE_READ_EA
FILE_TRAVERSE
FILE_READ_ATTRIBUTES
READ_CONTROL
SYNCHRONIZE
AceFlags...........OBJECT_INHERIT_ACE
CONTAINER_INHERIT_ACE
6. Trustee Name: Users
Trustee Domain: BUILTIN
Trustee SIDString: S-1-5-32-545
Ace (Access control entry) Type: Access Allowed
AccessMask.........FILE_ADD_SUBDIRECTORY
AceFlags...........CONTAINER_INHERIT_ACE
7. Trustee Name: Users
Trustee Domain: BUILTIN
Trustee SIDString: S-1-5-32-545
Ace (Access control entry) Type: Access Allowed
AccessMask.........FILE_ADD_FILE
AceFlags...........CONTAINER_INHERIT_ACE
Ende des Programmes F:\Daten\VBS\Berechtigungen_Auslesen.vbs, 3/2/2011
6:59:56 AM
***************
Trotzdem: Mit Google findet man unzählige Beispiele für C aber wieder nicht
für Basic!
Ein paar Fragen habe ich als Lernhilfe dazu trotzdem an Dich:
zB. unter
http://msdn.microsoft.com/de-de/library/system.security.accesscontrol.objectsecurity.getsecuritydescriptorbinaryform(v=vs.85).aspx
sind dazu die Definitionen beschrieben.
'Deklaration
Public Function GetSecurityDescriptorBinaryForm As Byte()
'Verwendung
Dim instance As ObjectSecurity
Dim returnValue As Byte()
returnValue = instance.GetSecurityDescriptorBinaryForm
1. Was ist mit
'Deklaration
Public Function GetSecurityDescriptorBinaryForm As Byte()
gemeint?
Muß **ich** die Funktion wie folgt deklarieren?
Declare Function GetSecurityDescriptorBinaryForm Lib "mscorlib.dll" () As
Byte()
Wenn ich weiter
Dim Objsecurity As ObjectSecurity
und
Dim retSecDescriptor As [Byte]()
definiere und anschließend zB.
retSecDescriptor = ObjSecurity.GetSecurityDescriptorBinaryForm
zuweisen möchte gibt es den Fehler
"Die Variable wird verwendet, bevor ihr ein Wert zugewiesen wird."
Kann ich das verhindern oder vernachlässigen?
Übrigens habe ich mit den Imports des Problem, welche ich zu welchem Zweck
zu importieren habe.
Als Besipiel (ich habe gegoogelt):
Imports System.Security.AccessControl
Imports System.Security.AccessControl.ObjectSecurity
um die Security?s benützen zu können.
Gibt es auch in der lokalen Hilfe dafür eine Unterstützung?
Danke
Wolfgang
Nein, das ist nur die Dokumentation der vorhandenen
Methode im Framework. Das gleiche siehst du auch
im Objektbrowser oder ggf per Intellisense.
> Declare Function GetSecurityDescriptorBinaryForm Lib "mscorlib.dll" () As
> Byte()
>
> Wenn ich weiter
> Dim Objsecurity As ObjectSecurity
> und
> Dim retSecDescriptor As [Byte]()
> definiere und anschließend zB.
>
> retSecDescriptor = ObjSecurity.GetSecurityDescriptorBinaryForm
>
> zuweisen möchte gibt es den Fehler
> "Die Variable wird verwendet, bevor ihr ein Wert zugewiesen wird."
>
> Kann ich das verhindern oder vernachlässigen?
Der Abschnitt in der Hilfe soll nur die Syntax zeigen.
Am besten ignorieren, denn wie man eine Funktion aufruft,
dürfte auch so bekannt sein. Du brauchst natürlich ein
object vom Typ ObjectSecurity, dessen Methode du aufrufst.
Da das eine "MustInherit"-Klasse ist, muss es eine
Instanz einer der erbenden Klassen sein. Damit müsstest
du dich aber erst einmal auseinandersetzen, denn der
Vererbungspfad z.B. der DirectorySecurity Klasse ist:
System.Object
System.Security.AccessControl.ObjectSecurity
System.Security.AccessControl.CommonObjectSecurity
System.Security.AccessControl.NativeObjectSecurity
System.Security.AccessControl.FileSystemSecurity
System.Security.AccessControl.DirectorySecurity
Letzteres bekommst du, wenn du die Methode GetAccessControl
eins System.IO.DirectoryInfo-Objekts aufrufst.
> Übrigens habe ich mit den Imports des Problem, welche ich zu welchem Zweck
> zu importieren habe.
Welches Problem?
Der Sinn von Imports im allgemeinen ist dir bekannt? Falls nicht:
Der Compiler löst ja die Namen "inside-out" auf, also er sucht
zuerst nach einem lokalen Bezeichner, dann auf Typ-Ebene, die
Vererbungshierarchie hinauf, die Verschachtelungsebene
(Typen+Namespaces) hinauf und schließlich in den importierten
Namespaces/Typen (zuerst die auf Dateiebene, dann die projektweiten
Importe). Ergo: "Imports" erspart also lediglich Tipparbeit
wenn man auf Bezeichner außerhalb des standardmäßigen Suchpfades
zugreifen will.
> Als Besipiel (ich habe gegoogelt):
>
> Imports System.Security.AccessControl
> Imports System.Security.AccessControl.ObjectSecurity
Einen Typ (im Gegensatz zu einem Namespace) zu importieren, bringt
dir nur etwas, wenn du die darin enthaltenen Typen oder Shared Members
ohne weitere Qualifizierung nutzen willst. Das wäre bei ObjectSecurity
lediglich die Methode IsSddlConversionSupported. Kannst du also
weglassen.
> um die Security?s benützen zu können.
>
> Gibt es auch in der lokalen Hilfe dafür eine Unterstützung?
Inwiefern? Meinst du das hier?
http://msdn.microsoft.com/en-us/library/ms229936(VS.90).aspx
Dürfte an derselben Stelle auch in der lokalen Hilfe stehen.
--
Armin
Jetzt weiß ich gar nicht, was Du meinst.
Wie richte ich diesen Vererbungspfad ein?
>
>> Übrigens habe ich mit den Imports des Problem, welche ich zu welchem
>> Zweck
>> zu importieren habe.
>
> Welches Problem?
>
> Der Sinn von Imports im allgemeinen ist dir bekannt?
> Importe). Ergo: "Imports" erspart also lediglich Tipparbeit
> wenn man auf Bezeichner außerhalb des standardmäßigen Suchpfades
> zugreifen will.
OK
>> Als Besipiel (ich habe gegoogelt):
>>
>
> Einen Typ (im Gegensatz zu einem Namespace) zu importieren,
Wie importiere ich einen Namespace, wie einen Typ?
Via COM oder Net Komponenten?
Wann Com, wann Net?
Was genau sind Assemblies wirklich?
Also in Löffelmanns Buch steht davon nichts.
Schon glaube ich, das falsche gekauft zu haben. 55,14 eine Fehlinvestition?
Alles was ich jetzt bräuchte steht dort nicht.
Es war eine Empfehlung aus dem Forum! :-()
Es wundert mich rückblickend nicht mehr, daß es wenige Monate später
mit Zustimmung von Microsoft Press umsonst heruntergeladen werden durfte.
> bringt dir nur etwas, wenn du die darin enthaltenen Typen oder Shared
> Members
> ohne weitere Qualifizierung nutzen willst. Das wäre bei ObjectSecurity
> ledbringtiglich die Methode IsSddlConversionSupported. Kannst du also
> weglassen.
Wie aber beseitige ich konkret den Fehler,
das Objekt wird verwendet ohne vorher belegt zu werden?
>
>> um die Security?s benützen zu können.
>>
>> Gibt es auch in der lokalen Hilfe dafür eine Unterstützung?
>
> Inwiefern? Meinst du das hier?
>
> http://msdn.microsoft.com/en-us/library/ms229936(VS.90).aspx
>
JA.
> Dürfte an derselben Stelle auch in der lokalen Hilfe stehen.
Danach werde ich noch suchen.
Es gibt, wie ich nun feststellen muß, sehr große Verständnisprobleme zu VS
Net.
Die Begriffe und ihre Bedeutungen sind mir, so sieht es jetzt immer
deutlicher aus, gar nicht klar.
Jeder Erklärungsversuch Deinerseits wirft mehr Fragen auf als er
beantwortet.
VS Net ist nichts mehr für bloß Neugierige.
Es ist eine Sprache für gediegen ausgebildete Profis mit langjähriger
Erfahrung.
So nebenher läßt sich hier nichts mehr machen.
Das ist von MS offenbar auch so erwünscht gewesen.
Dagegen ist VBA, wie auch in Access verwendet, eine simple Skriptsprache.
8 Jahre VS ist aber auch schon eine lange Zeit.
Den Anschluß habe ich anscheinend schon verpaßt. Ich bin jetzt eigentlich
sehr verzagt.
Danke zunächst.
Die Acces-Control lasse ich fürs erste weg und werde ausnahmsweise als Admin
weiter entwickeln.
Den Pfad des gemounteten Sticks gilt es ja noch zu ermitteln.
Es ist ein wirklich schwieriger Weg, da mir vieles über VB einfach fremd ist
und mir die Zusammenhänge fehlen.
Was ein Namespace und eine Assembly wirklich sind und wozu sie dienen, ist
mir nun überhaupt nicht mehr klar.
Trotzdem:
Als nächstes habe ich versucht, die VID und PID mittels Handle aus
CreateFile zu ermitteln:
Der Aufruf der Function HidD_GetAttributes klemmt.
Declare Function HidD_GetAttributes Lib "HID.dll" _
(ByVal Handle As Win32.SafeHandles.SafeFileHandle, _
<[In](), [Out]()> ByRef Attributes As HIDD_ATTRIBUTES) _
As Boolean
aus http://msdn.microsoft.com/en-us/library/ff538900(v=vs.85).aspx
Könnte Handle As Win32.SafeHandles.SafeFileHandle ev. schon falsch sein?
Diesen liefert doch CreateFile?
dazu die Struktur
<StructLayout(LayoutKind.Sequential, pack:=2)> _
Public Structure HIDD_ATTRIBUTES
Public Size As UInt32
Public VendorID As UShort
Public ProductID As UShort
Public VersionNumber As UShort
End Structure
Zur Erinnerung noch die Function
Public Declare Auto Function CreateFile Lib "kernel32.dll" ( _
<MarshalAs(UnmanagedType.LPTStr)> ByVal lpFileName As String, _
ByVal DesiredAccess As UInt32, _
ByVal ShareMode As UInt32, _
ByVal SecurityAttributes As IntPtr, _
ByVal CreationDisposition As UInt32, _
ByVal FlagsAndAttributes As UInt32, _
ByVal hTemplateFile As IntPtr) _
As Win32.SafeHandles.SafeFileHandle
jetzt die Definitionen in Form1_Load
Dim FileHandle As Win32.SafeHandles.SafeFileHandle
Dim DeviceAttributes As HIDD_ATTRIBUTES
DeviceAttributes.Size = CUInt(Marshal.SizeOf(DeviceAttributes)) ' = 10
Aufruf CreateFile
FileHandle = CreateFile(strDetailData, _
GENERIC_READ, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, _
IntPtr.Zero, _
OPEN_EXISTING, 0, IntPtr.Zero)
FileHandle.IsInvalid = False
und nun kommt's:
bRetc = HidD_GetAttributes(FileHandle, DeviceAttributes)
If bRetc Then
strFormat = String.Format("VID: <{0}>, PID: <{1}>, ", _
DeviceAttributes.VendorID, DeviceAttributes.ProductID)
lstTrace.Items.Add(strFormat)
Trace.WriteLine(strFormat)
End If
bRetc ist für alle Massenspeicher false.
Spezifiziert FileHandle wirklich eine
"Specifies an open handle to a top-level collection."?
Was ist eine top-level collection? Ich dachte ein Handle ist ein Merkmal zu
einem geöffneten File?
Liegt da etwa der Hund schon begraben?
noch zur Kontrolle
DeviceAttributes.Size = 10 ' geprüft!
Vielleicht siehst Du den Mangel auf Anhieb.
Schön langsam frage ich mich, ob ich über VB .net nicht einfach zu wenig
weiß.
Doch woher die Informationen bekommen. Seminare, Bücher?
Das Internet ist als Quelle dafür offenbar schlecht geeignet.
Vielleicht sollte ich all das doch besser in VB6 realisieren. Das Eis ist
hier sehr dünn für mich!
Danke,
Wolfgang
Eigentlich nur Banales!
Wenn ich als Admin VS 2008 nutze, kann ich bestimmte Befehle
der Symbolleiste nicht anzeigen und bestimmte Menupunkte mangels
Vorhandensein nicht verwenden:
Aus den Befehlen Erstellen\Projektmappenkonfigurationen kann ich die
Projektmappenkonfigurationen zwar als Icon in die Symbolleiste holen, aber
das Icon ist immer ausgegraut.
Deshalb kann ich weder Release, Debug auswählen aber den
Konfigurationsmanager nicht starten.
Genauso mit der Projektmappenplattformen: eine Auswahl nach Any CPU
oder Konfigurationsmanager ist nicht möglich.
Unter dem Menupunkt Erstellen kann man am Ende der Dropdownliste den
Menüpunkt Konfigurationsmanager
mangels Anzeige desselben nicht anwählen.
Das heißt, ich kann **nirgends** Einstellungen betr. die Konfiguration
vornehmen.
Weiters wird die Hilfe immer als eigenes Fenster geöffnet.
Die Hilfe als Tab anzeigen zu lassen will mir nicht gelingen.
Daher läßt sich der Hilfeindex auch nicht am Code-Fenster andocken,
nur im Hilfefenster selbst.
Das läßt sich minimieren und vergrößern, aber das wars dann auch schon.
Was als eingeschränkter User ganz einfach zum Einstellen ging, geht als
Admin gar nicht.
An welchen Schrauben muß ich drehen, damit ich als Admin dieselben
Menu-Unterpunkte und Symbolleisten
anzeigen und verwenden kann wie als normaler User?
Dies alles ist mir natürlich bisher gar nicht aufgefallen.
Schön langsam verzweifle ich mit dem VS 2008!
Bitte um Unterstützung,
Wolfgang
Den gibt es schon. :-) Das sind Klassen im Framework.
- CommonObjectSecurity erbt von ObjectSecurity.
- NativeObjectSecurity erbt von CommonObjectSecurity.
- usw.
> Wie importiere ich einen Namespace, wie einen Typ?
Imports System.Security.AccessControl 'Namespace
Imports System.Security.AccessControl.ObjectSecurity 'Typ
> Via COM oder Net Komponenten?
> Wann Com, wann Net?
COM ist eine alternative Technologie. Wenn du es
in einer .Net-Anwendung nicht (explizit) brauchst,
dann musst du dich damit auch nicht beschäftigen.
Damit eine .Net-Anwendung auf COM-Komponenten zugreifen
kann bedarf es einer Zwischenschicht. Die Themen
"COM" und Plattformaufruf (also z.B. Aufruf von
API-Funktionen) bilden das Oberthema "Interop":
http://msdn.microsoft.com/en-us/library/ms172270(VS.90).aspx
> Was genau sind Assemblies wirklich?
Exen und Dlls. Genauer:
http://msdn.microsoft.com/en-us/library/hk5f40ct(VS.90).aspx
> Wie aber beseitige ich konkret den Fehler,
> das Objekt wird verwendet ohne vorher belegt zu werden?
Indem du der Variablen einen Wert zuweist. Bsp.:
Falsch:
dim s as string
dim i as integer
i = s.length 'Fehler: NullReferenceException
Richtig:
dim s as string
dim i as integer
s = "abc"
i = s.length 'OK
> VS Net ist nichts mehr für bloß Neugierige.
> Es ist eine Sprache für gediegen ausgebildete Profis mit langjähriger
> Erfahrung.
Auf Dein Vorhaben trifft das wahrscheinlich zu. Im allgemeinen muss man
natürlich erst die Grundlagen beherrschen, bevor man etwas angeht.
Diese sind sicher umfangreicher, als es früher der Fall war, aber das
ist nun mal so, wenn es mehr Möglichkeiten geben soll.
> Ich bin jetzt eigentlich sehr verzagt.
Du hast doch schon viel gemacht! Nach meiner Einschätzung bist
du schon relativ weit. Ich habe in der Englisch-sprachigen Gruppe
zuletzt mit einem 70-jährigen Australier zu tun gehabt. Er war
jedoch nicht bereit, zuerst einmal die Grundlagen zu lernen.
Ich habe das letztendlich auch akzeptiert und dabei gelernt,
dass es nicht nur verschiedene Einstiege und Wege zum Ziel
gibt, sondern dass nicht jeder unbedingt zum Ziel gelangen will.
Dazu zähle ich dich aber nicht.
> Was ein Namespace und eine Assembly wirklich sind und wozu sie dienen, ist
> mir nun überhaupt nicht mehr klar.
Crash-Kurs:
I. Projektsturktur
1.
Eine Anwendung besteht aus einer Exe und Dlls (Oberbegriff: Assemblies).
Das ist die /physikalische/ Sicht.
2. Aus /programmiertechnischer/ Sicht besteht eine Anwendung bzw ein Projekt
aus /Typ-Deklarationen/. Das sind Deklarationen von Klassen, Strukturen,
Enums, Interfaces und Delegates. Zum Projekt gehören alle eigenen
Deklarationen und alle Deklarationen in allen referenzierten Assemblies.
Um bei einer großen Anzahl von Typ-Deklarationen den Überblick
zu behalten, gibt es die Möglichkeit, sie in Namespaces einzusortieren.
Das ist vergleichsweise so, wie wenn man die Dateien auf der Festplatte
nicht alle im Hauptverzeichnis liegen hat sondern Ordner anlegt und
die Dateien darunter einsortiert. Und genauso, wie man in einem Ordner
nochmals Unterordner anlegen kann, kann man auch in einem Namespace
weitere untergeordnete Namespaces anlegen. Ergebnis ist eine
Baumstruktur bestehend aus Namespaces (analog zu den Ordnern) und
darin enthaltenen Typ-Deklarationen (analog zu den Dateien).
Ergo: Ein Projekt besteht aus einem Baum von Namespaces und Typen
sowohl der referenzierten Dlls als auch der eigenen Dll/Exe.
Hinzu kommt, dass man innerhalb einer Klassen- oder Struktur-
Deklaration weitere Typ-Deklarationen machen kann. Das ist aber
nur ein weitere Ast im Baum und ändert nichts am Gesamtbild.
Beispiel: (Namespaces mit "{}" gekennzeichnet)
{System}
Klasse "Environment"
Klasse "NullReferenceException"
{Collections}
Klasse "ArrayList"
Klasse "Queue"
{Windows}
{Forms}
Klasse "Control"
Klasse "Form"
{USBDetector}
{UI}
{Forms}
Klasse "MainForm"
Klasse "InfoForm"
{Controls}
Klasse "DeviceList"
{Worker}
Klasse "Main"
Klasse "WatWeißIch"
Structure "NestedStructure"
Klasse "NochNeKlasse"
3. Die dritte Sicht auf ein Projekt ist die Vererbungshierarchie
mit dem Typ System.Object an der Spitze. Alle oben genannten
Typ-Arten (Klassen, Strukturen, Enums, Delegates) außer den
Interfaces erben direkt oder indirekt von System.Object.
Beispiel für den Enum-Typ System.Windows.Forms.BorderStyle:
System.Object
System.ValueType
System.Enum
System.Windows.Forms.BorderStyle
Beispiel für den Struktur-Typ System.Drawing.Point:
System.Object
System.ValueType
System.Drawing.Point
Beispiel für den Delegate-Typ System.Windows.Forms.MouseEventHandler:
System.Object
System.Delegate
System.MulticastDelegate
System.Windows.Forms.MouseEventHandler
Die Vererbungshierarchie darf man nicht mit dem Verschachtelungsbaum
aus Punkt 2 verwechseln!
> Trotzdem:
> Als nächstes habe ich versucht, die VID und PID mittels Handle aus
> CreateFile zu ermitteln:
>
> Der Aufruf der Function HidD_GetAttributes klemmt.
> Declare Function HidD_GetAttributes Lib "HID.dll" _
> (ByVal Handle As Win32.SafeHandles.SafeFileHandle, _
> <[In](), [Out]()> ByRef Attributes As HIDD_ATTRIBUTES) _
> As Boolean
> aus http://msdn.microsoft.com/en-us/library/ff538900(v=vs.85).aspx
> Könnte Handle As Win32.SafeHandles.SafeFileHandle ev. schon falsch sein?
> Diesen liefert doch CreateFile?
Wenn du als Pfad "\\?\USBSTOR...." an CreateFile übergibst,
dann bekommst du dein Handle zu einem /Device/. Die Funktion
erwartet hingegen ein Handle zu einer "Top-level Collection"
(s. Doku). Das hat nichts miteinander zu tun.
Mit dem Handle von CreateFile kannst du über die API-Funktion
DeviceIOControl auf das Gerät zugreifen:
http://msdn.microsoft.com/en-us/library/aa363216(VS.85).aspx
Es gibt diverse Steuercodes, die du an die Funktion übergeben
kannst. Siehe Links unten auf der verlinkten Seite.
> Spezifiziert FileHandle wirklich eine
> "Specifies an open handle to a top-level collection."?
> Was ist eine top-level collection? Ich dachte ein Handle ist ein Merkmal zu
> einem geöffneten File?
"File" ist hier nicht so eng zu sehen. In dem Fall ist es
das Handle zu einem Device.
> Liegt da etwa der Hund schon begraben?
Ja.
> noch zur Kontrolle
> DeviceAttributes.Size = 10 ' geprüft!
>
> Vielleicht siehst Du den Mangel auf Anhieb.
>
> Schön langsam frage ich mich, ob ich über VB .net nicht einfach zu wenig
> weiß.
Nein. Was die Aufgabenstellung angeht, hat das nichts
mit dem Wissen über VB zu tun sondern über die Materie,
die wir in den letzten Tagen "verarbeitet" haben.
> Doch woher die Informationen bekommen. Seminare, Bücher?
> Das Internet ist als Quelle dafür offenbar schlecht geeignet.
>
> Vielleicht sollte ich all das doch besser in VB6 realisieren. Das Eis ist
> hier sehr dünn für mich!
Was sollte denn damit besser gehen?
--
Armin
Den Punkt habe ich nicht. Ich habe Erstellen\Konfigurationsmanager falls
du den meinst.
Mail mir bitte mal nen Screenshot von den Problemchen.
Kann's mir schwer vorstellen.
Auf jeden Fall solltest du unter Menü Extras -> Optionen
unten den Punkt "[X] Alle Einstellungen anzeigen" wählen.
Dann, ebenfalls in den Optionen, links unter "Projekte und Projektmappen"
(ganz nach oben scrollen!) die Option "Erweiterte Buildkonfigurationen
anzeigen" ankreuzen. Vielleicht war's das schon.
Nicht verzweifeln! Das kriegen wir schon hin.
Du kannst mir auch weiterhin mailen, falls du meinst, dass
das für hier zu banal sei. Hier ist aber sonst sowieso
nichst mehr los.
--
Armin
Ich ziehe meine Aussage zurück...
In dieser Richtung habe ich mich noch nicht damit beschäftigt.
Du scheinst also Recht damit zu haben, dass das Handle
auch an die HidD_ Funktionen und nicht nur an DeviceIoControl
übergeben werden kann. Muss ich mir noch genauer ansehen.
--
Armin
Noch eine Frage: Wenn du die HidD-Funktionen verwendest,
wie willst du dann auf einen USB-Stick kommen? Ich dachte
bisher, das sind verschiedene Themen. Mit der Device-InterfaceClass
HID bekomme ich Maus+Tastatur aber keinen USB-Stick.
--
Armin
Ich habe nochmals bei Löffelmann nachgelesen.
Es steht zu Assemblies und Namespaces wenig drinnen, aber eines habe ich
mitgekriegt:
Man kann die Imports weglassen, indem man die Namespaces einbindet.
Habe ich so eingebaut. Intellisens funktioniert wie vorher mit den Imports.
Warum eigentlich werden bei Imports nicht gleich die Namespaces eingebunden?
Wäre mir irgendwie verständlicher.
Zwei voneinander unabhängige Ebenen sind verwirrend.
>> Via COM oder Net Komponenten?
>> Wann Com, wann Net?
>
> COM ist eine alternative Technologie. Wenn du es
> in einer .Net-Anwendung nicht (explizit) brauchst,
> dann musst du dich damit auch nicht beschäftigen.
> Damit eine .Net-Anwendung auf COM-Komponenten zugreifen
> kann bedarf es einer Zwischenschicht. Die Themen
> "COM" und Plattformaufruf (also z.B. Aufruf von
> API-Funktionen) bilden das Oberthema "Interop":
OK.
> Exen und Dlls. Genauer:
> http://msdn.microsoft.com/en-us/library/hk5f40ct(VS.90).aspx
>
Habe ich schon gefunden und hoffentlich auch auf Dauer gemerkt.
>> Wie aber beseitige ich konkret den Fehler,
>> das Objekt wird verwendet ohne vorher belegt zu werden?
>
> Indem du der Variablen einen Wert zuweist. Bsp.:
>
> Falsch:
> dim s as string
> dim i as integer
>
> i = s.length 'Fehler: NullReferenceException
>
> Richtig:
> dim s as string
> dim i as integer
>
> s = "abc"
>
> i = s.length '
OK
Das verstehe ich. Aber wie ist das dabei:
Definiert ist
Dim retSecDescriptor As [Byte]()
Dim ObjSecurity As ObjectSecurity
Wie soll ich nun ObjSecurity einen Wert zuweisen?
ObjSecurity = ?????
oder
Dim ObjSecurity As ObjectSecurity = ????
>
> Auf Dein Vorhaben trifft das wahrscheinlich zu. Im allgemeinen muss man
> natürlich erst die Grundlagen beherrschen, bevor man etwas angeht.
> Diese sind sicher umfangreicher, als es früher der Fall war, aber das
> ist nun mal so, wenn es mehr Möglichkeiten geben soll.
>
Ich bin bei Löffenmann bei LINQ angelangt, das ist Seite 857.
Aber die "Grundlagen" sind mir noch sehr fremd.
Ich werde das versuchen nachzuholen.
>> Ich bin jetzt eigentlich sehr verzagt.
>
> Du hast doch schon viel gemacht! Nach meiner Einschätzung bist
> du schon relativ weit. Ich habe in der Englisch-sprachigen Gruppe
> zuletzt mit einem 70-jährigen Australier zu tun gehabt. Er war
> jedoch nicht bereit, zuerst einmal die Grundlagen zu lernen.
Offenbar aber noch nicht genug.
>
>
>> Was ein Namespace und eine Assembly wirklich sind und wozu sie dienen,
>> ist
>> mir nun überhaupt nicht mehr klar.
Hier möchte ich ergänzen, daß die miteinander nicht hierarchisch in
Verbindung stehenden
Begriffe Namespace und Assembly nicht einfach veständlich sind.
Löffelmann sagt, Namespaces sind die Kapitel eines Buches.
Und die Assemblies sind das Buch? Also doch hierarchisch miteinander in
Verbindung?
Genau das ist es was ich nicht verstehe.
Wozu die Trennung in ein konkretes und ein abstraktes Modell?
>
> Crash-Kurs:
>
> I. Projektsturktur
>
> 1.
> Eine Anwendung besteht aus einer Exe und Dlls (Oberbegriff: Assemblies).
> Das ist die /physikalische/ Sicht.
Also die eigentlichen Daten eines Projektes?
Puh...
Also jetzt passe ich noch, aber ich werde Deinen Ausführungen auf den Grund
gehen, hinabtauchen.
>
Dachte ich doch.
Allerdings woher soll ich zunächst wissen was eine "top-level collection"
ist?
Ich werde den Link
http://msdn.microsoft.com/en-us/library/aa363216(VS.85).aspx
ausführlich studieren, denn ohne ihn geht es ja nicht weiter.
>>
>> Schön langsam frage ich mich, ob ich über VB .net nicht einfach zu wenig
>> weiß.
>
> Nein. Was die Aufgabenstellung angeht, hat das nichts
> mit dem Wissen über VB zu tun sondern über die Materie,
> die wir in den letzten Tagen "verarbeitet" haben.
Tut diese Aussage gut!
>
> Was sollte denn damit besser gehen?
>
Das habe ich auch schon überlegt.
Also doch VS2008!
Danke,
Wolfgang
Das ist ganz lieb von Dir.
Dann sollte das so eigentlich gehen?
Wolfgang
"Armin Zingler" <az.n...@freenet.de> wrote in message
news:8t83n9...@mid.uni-berlin.de...
Offenbar aber nicht nur für diese HID?s.
Mit diesem Funktionaufruf sollte man VID und PID erhalten, las ich.
Diese Daten hat auch ein USB-Massenspeicher.
Das kann natürlich auch ganz falsch sein.
Doch sollte man mit VID und PID die Seriennummer ermitteln können und dann
letztendlich den Pfad.
Ich hoffe sehr, daß ich mich da nicht verrannt habe.
Wolfgang
> Den Punkt habe ich nicht. Ich habe Erstellen\Konfigurationsmanager falls
> du den meinst.
Kann ich Dir nicht mehr schießen.
Inzwischen habe die Einstellungen des Users in die IDE des Admin importiert.
Nun ist mit beiden LogIns die Oberfläche diesselbe.
Wie ich es genau als User eingestellt habe ist einfach zu lange her.
Und selbsterklärend sind diese Einstellungen nicht ganz.
Vor allem wenn sie **nicht** gehen.
>
> Nicht verzweifeln! Das kriegen wir schon hin.
> Du kannst mir auch weiterhin mailen, falls du meinst, dass
> das für hier zu banal sei. Hier ist aber sonst sowieso
> nichst mehr los.
Also besten Dank für die Ausführungen
Wolfgang.
PS: jetzt geht es weiter in die Richtung Pfade zum USB-Massenspeicher
ermitteln.
Was meinst du mit "einbinden"? Meinst du die Angabe des vollen Namens?
Thema "Namensauflösung" wäre Kapitel II meines Crash-Kurses gewesen. ;-)
Da ich das schon in einem Satz zusammenfassend beschrieben hatte,
habe ich dir das erspart.
> OK
> Das verstehe ich. Aber wie ist das dabei:
>
> Definiert ist
> Dim retSecDescriptor As [Byte]()
> Dim ObjSecurity As ObjectSecurity
>
>
> Wie soll ich nun ObjSecurity einen Wert zuweisen?
> ObjSecurity = ?????
> oder
> Dim ObjSecurity As ObjectSecurity = ????
Kommt darauf an, von welchem Objekt du die Security ermitteln willst.
Am Beispiel eines Verzeichnisses:
Dim DI As New IO.DirectoryInfo("d:\benutzer")
Dim ObjSecurity As Security.AccessControl.DirectorySecurity 'erbt von ObjectSecurity
ObjSecurity = di.GetAccessControl()
Mit den Methoden des DirectorySecurity-Objekts lässt sich dann z.B.
der Besitzer des Verzeichnisses, die Überwachungsrichtlinien und
die Zugriffsrechte ermitteln oder ändern.
>> Auf Dein Vorhaben trifft das wahrscheinlich zu. Im allgemeinen muss man
>> natürlich erst die Grundlagen beherrschen, bevor man etwas angeht.
>> Diese sind sicher umfangreicher, als es früher der Fall war, aber das
>> ist nun mal so, wenn es mehr Möglichkeiten geben soll.
>>
> Ich bin bei Löffenmann bei LINQ angelangt, das ist Seite 857.
> Aber die "Grundlagen" sind mir noch sehr fremd.
> Ich werde das versuchen nachzuholen.
Wenn du meinst, die Grundlagen noch nicht zu beherrschen,
empfehle ich, LINQ erst einmal komplett beiseite zu lassen.
Ist ja erst mit VB 2005 eingeführt worden. Wenngleich
es manchmal ziemlich hilfreich ist, kann man sehr gut auch
ohne leben.
> Hier möchte ich ergänzen, daß die miteinander nicht hierarchisch in
> Verbindung stehenden
> Begriffe Namespace und Assembly nicht einfach veständlich sind.
> Löffelmann sagt, Namespaces sind die Kapitel eines Buches.
> Und die Assemblies sind das Buch? Also doch hierarchisch miteinander in
> Verbindung?
> Genau das ist es was ich nicht verstehe.
> Wozu die Trennung in ein konkretes und ein abstraktes Modell?
Weil es sich beim einen um Dateien auf der Platte, beim anderen
um Elemente der Programmierung handelt. Das sind völlig unterschiedliche
/Schichten/, denn weder weiß NTFS davon, dass in den Dlls Klassen liegen
- das muss es auch nicht wissen - noch interessiert mich (i.d.R.)
während der Programmierung, in welchen Dlls meine verwendeten Typen
liegen. Klar, wenn ich eine Klasse benötige, muss ich einen Verweis
auf die enthaltende Dll setzen, aber damit hat es sich auch schon.
Ab dann gehört die Klasse zum Projekt und zu einer logischen
Projektstruktur bestehend aus Namespaces und Typen, und nur in dieser
bewege ich mich während der Programmierung.
Dass das zwei unterschiedliche Sichten sind, sieht man auch
daran, dass sich einerseits die Typen desselben Namespaces in
verschiedenen Dlls befinden können, andererseits eine Dll
mehrere Namespaces enthalten kann. Beispiel: Die Bestandteile des
Namespaces "System" sind über die Bibliotheken mscorlib.dll,
system.dll, System.Core.dll, u.a. verstreut.
An der System.Core.dll sieht man auch schön, warum diese Möglichkeit
sinnvoll ist: Die System.Core.Dll gibt es erst ab Framework 3.5.
Der Hersteller kann also seinen Namespace "System", wie er im FW 2.0
geliefert wurde, erweitern, indem er neue Dlls zur Verfügung stellt.
Ich selbst habe auch die Elemente in meinem Basis-Namespace "AZ" in
verschiedenen Dlls liegen. Für's eine Projekt brauche ich nur die
eine Dll, für ein anderes eine andere Dll. Somit muss ich beim
jeweiligen Projekt auch nur die jeweils benötigte Dll ausliefern.
Öffne mal den Objektbrowser (hier: [F2]). Wenn du im linken Panel
rechts-klickst, kannst du die Ansicht "Namespaces anzeigen"
oder "Container anzeigen" wählen. Probiere beide mal aus.
Mit anderen Worten: Die Kriterien zur Strukturierung unterscheiden
sich zwischen den Schichten weil es um andere Elemente geht.
Oder so:
Du kannst dir auch zwei Container hinstellen. Ein beschriften
mit "privat" den anderen mit "geschäftlich". In beiden sind Blumen
und Möbel enthalten. Wenn privat und geschäftlich räumlich getrennt
sind, würde es dir nichts bringen, alle Blumen in einen Container
und alle Möbel in den anderen zu stellen. Das wäre vielleicht
schön aufgräumt aber eben nicht zweckmäßig.
>> 1.
>> Eine Anwendung besteht aus einer Exe und Dlls (Oberbegriff: Assemblies).
>> Das ist die /physikalische/ Sicht.
>
> Also die eigentlichen Daten eines Projektes?
Alles. Das gesamte Projekt. Natürlich in kompilierter Form.
Natürlich kann es noch weitere zum Projekt gehörende
Dateien geben (aber das ist ja jetzt nicht das Thema).
>> Beispiel: (Namespaces mit "{}" gekennzeichnet)
>>
>> {System}
>> Klasse "Environment"
>> Klasse "NullReferenceException"
>> {Collections}
>> Klasse "ArrayList"
>> Klasse "Queue"
>> {Windows}
>> {Forms}
>> Klasse "Control"
>> Klasse "Form"
>> {USBDetector}
>> {UI}
>> {Forms}
>> Klasse "MainForm"
>> Klasse "InfoForm"
>> {Controls}
>> Klasse "DeviceList"
>> {Worker}
>> Klasse "Main"
>> Klasse "WatWeißIch"
>> Structure "NestedStructure"
>> Klasse "NochNeKlasse"
> Puh...
> Also jetzt passe ich noch, aber ich werde Deinen Ausführungen auf den Grund
> gehen, hinabtauchen.
Das Projekt ist ein Baum aus Namespaces und Typen.
Mehr ist dann auch nicht zu verstehen. :-)
Die Vererbungshierarchie ist, wie geschrieben, ein ganz anderer Film.
Beispielsweise erbt die Klasse System.Windows.Forms.Form von
der Klasse System.Windows.Forms.Control. Dennoch sind beide
Klassen völlig gleichwertig im selben Namespace enthalten.
Keine Sorge, das ist keine neue Info sondern nur ein Beispiel
für das bereits Geschriebene.
> Also doch VS2008!
Jo, besser ist das.
--
Armin
Meinst du die Angabe des vollen Namens?
> Thema "Namensauflösung" wäre Kapitel II meines Crash-Kurses gewesen. ;-)
> Da ich das schon in einem Satz zusammenfassend beschrieben hatte,
> habe ich dir das erspart.
>
Natürlich!
>
>> Definiert ist
>> Dim retSecDescriptor As [Byte]()
>> Dim ObjSecurity As ObjectSecurity
>>
>>
>> Wie soll ich nun ObjSecurity einen Wert zuweisen?
>> ObjSecurity = ?????
>> oder
>> Dim ObjSecurity As ObjectSecurity = ????
>
>
> Kommt darauf an, von welchem Objekt du die Security ermitteln willst.
> Am Beispiel eines Verzeichnisses:
>
> Dim DI As New IO.DirectoryInfo("d:\benutzer")
> Dim ObjSecurity As Security.AccessControl.DirectorySecurity 'erbt
> von ObjectSecurity
>
> ObjSecurity = di.GetAccessControl()
>
> Mit den Methoden des DirectorySecurity-Objekts lässt sich dann z.B.
> der Besitzer des Verzeichnisses, die Überwachungsrichtlinien und
> die Zugriffsrechte ermitteln oder ändern.
Also das muß ich jetzt erst einmal verdauen!
In ggst. Fall geht es um das Ermitteln des Securitydescriptors
>> Ich bin bei Löffenmann bei LINQ angelangt, das ist Seite 857.
>> Aber die "Grundlagen" sind mir noch sehr fremd.
>> Ich werde das versuchen nachzuholen.
>
> Wenn du meinst, die Grundlagen noch nicht zu beherrschen,
> empfehle ich, LINQ erst einmal komplett beiseite zu lassen.
> Ist ja erst mit VB 2005 eingeführt worden. Wenngleich
> es manchmal ziemlich hilfreich ist, kann man sehr gut auch
> ohne leben.
Sehe ich auch so.
Bei Namespaces anzeigen werden die darunterliegenden
Hierarchien nicht angezeigt, bei Container anzeigen schon.
Also kann ich in dieser Übersicht, die Hierarchien er Objekte eines
Namespaces ersehen.
Gut zu wissen.
>
> Mit anderen Worten: Die Kriterien zur Strukturierung unterscheiden
> sich zwischen den Schichten weil es um andere Elemente geht.
>
> Oder so:
> Du kannst dir auch zwei Container hinstellen. Ein beschriften
> mit "privat" den anderen mit "geschäftlich". In beiden sind Blumen
> und Möbel enthalten. Wenn privat und geschäftlich räumlich getrennt
> sind, würde es dir nichts bringen, alle Blumen in einen Container
> und alle Möbel in den anderen zu stellen. Das wäre vielleicht
> schön aufgräumt aber eben nicht zweckmäßig.
So wirds schon verständlicher!
>
>>> 1.
>>> Eine Anwendung besteht aus einer Exe und Dlls (Oberbegriff: Assemblies).
>>> Das ist die /physikalische/ Sicht.
>>
>> Also die eigentlichen Daten eines Projektes?
>
> Alles. Das gesamte Projekt. Natürlich in kompilierter Form.
> Natürlich kann es noch weitere zum Projekt gehörende
> Dateien geben (aber das ist ja jetzt nicht das Thema).
>
> Das Projekt ist ein Baum aus Namespaces und Typen.
> Mehr ist dann auch nicht zu verstehen. :-)
Leichter gesagt als verstanden.
>
> Die Vererbungshierarchie ist, wie geschrieben, ein ganz anderer Film.
> Beispielsweise erbt die Klasse System.Windows.Forms.Form von
> der Klasse System.Windows.Forms.Control. Dennoch sind beide
> Klassen völlig gleichwertig im selben Namespace enthalten.
> Keine Sorge, das ist keine neue Info sondern nur ein Beispiel
> für das bereits Geschriebene.
Ich gebe die Hoffnung noch nicht auf.
Wolfgang
Richtig, dort kannst du sowohl Verweise hinzufügen als auch Namespaces
/projektweit/ importieren. Die Imports-Anweisung gilt hingegen nur für
die Datei, in der sie steht. Das Importieren hat zwar den Vorteil, sich
Tipparbeit zu sparen, jedoch steigt das Risiko von Namenskonflikten
oder Verwechslungen. Deswegen gibt es eben beide Möglichkeiten.
> In ggst. Fall geht es um das Ermitteln des Securitydescriptors
Wenn ich danach suche, finde ich das als einen Typ eines
Device-Properties im WDK. Mit dem .Net Framework kommst du da
aber nicht weit. Es gibt zwar den Namespace System.Management,
aber der baut auf WMI auf, womit wir wieder am Anfang wären.
Den Link will ich dir trotzdem nicht vorenthalten:
http://msdn.microsoft.com/en-us/library/system.management.aspx
>> Öffne mal den Objektbrowser (hier: [F2]). Wenn du im linken Panel
>> rechts-klickst, kannst du die Ansicht "Namespaces anzeigen"
>> oder "Container anzeigen" wählen. Probiere beide mal aus.
>
> Bei Namespaces anzeigen werden die darunterliegenden
> Hierarchien nicht angezeigt, bei Container anzeigen schon.
>
> Also kann ich in dieser Übersicht, die Hierarchien er Objekte eines
> Namespaces ersehen.
> Gut zu wissen.
Du hast Recht, die Namespaces werden nicht verschachtelt sondern
untereinander angezeigt, z.B. System.Collections unterhalb von System
auf gleicher Ebene und nicht als Unterknoten. Das ist aber nur die
Form der Darstellung im Objektbrowser. Ich schätze, diese Form
wurde gewählt, um schneller an die einzelnen Elemente zu gelangen
ohne sich über zig Unterknoten durchwühlen zu müssen. Meine
Baumdarstellung würde ich trotzdem im Hinterkopf behalten.
> Ich gebe die Hoffnung noch nicht auf.
So wie du hier eingestiegen bist, mache ich mir da überhaupt keine
Sorgen. (die mache ich mir sowieso nicht. ;) )
--
Armin
> So wie du hier eingestiegen bist, mache ich mir da überhaupt keine
> Sorgen. (die mache ich mir sowieso nicht. ;) )
Vielleicht bleibt alles Gelesene lange hängen!
Danke
Wolfgang
Bei der Definition von DeviceIoControl
bin ich auf die Definition von
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
} ;
struct {
DWORD LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER, *PLARGE_INTEGER;
gestoßen.
Weißt Du, wie ich diese Struktur in VB definieren muß?
Dann noch eine grundsätzliche Frage:
Strukturen, Tabellen sind doch Verweistypen.
Wenn ich diese in einem Declare Stmt ansprechen möchte, muß
ich **immer** ByRef verwenden.
Bei Wertetypen wie zB. für int32 gibt es dann zwei Varianten:
ByVal Wert As int32 ' als zu übergebender Wert
ByRef Wert As int32 ' als zu übergebender Wert per Referenz
Für Pointer müßte dann immer
**ByVal** Pointer As IntPtr ' als zu übergebender Wert per Pointer
gelten?
Danke,
Wolfgang
Einfach nur "As Long". Da die Elemente Alternativen sind,
kannst du auch nur den LONGLONG-Part beachten, und der
ist "64-bit signed integer" wie hier geschrieben:
http://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx
Oder alternativ:
<StructLayout(LayoutKind.Explicit)> _
Structure LargeInteger
<FieldOffset(0)> Public LowPart As Integer
<FieldOffset(4)> Public HighPart As Integer
<FieldOffset(0)> Public QuadPart As Long
End Structure
Fertige Deklarationen findest du auch hier:
http://pinvoke.net
Ich würde mich aber nicht immer drauf verlassen! Also kopieren,
um Tipparbeit zu sparen, dann aber nochmal prüfen.
Bei LARGE_INTEGER gibt's keine für VB:
http://pinvoke.net/default.aspx/Structures.LargeInteger
> Dann noch eine grundsätzliche Frage:
>
> Strukturen, Tabellen sind doch Verweistypen.
Strukturen (Structures) sind _Wertetypen_.
Bei Tabellen weiß ich nicht, welche du meinst. Klassen
sind Verweistypen.
> Wenn ich diese in einem Declare Stmt ansprechen möchte, muß
> ich **immer** ByRef verwenden.
Wenn ein Pointer auf einen Wertetyp erwartet wird, dann musst
du ByRef verwenden.
> Bei Wertetypen wie zB. für int32 gibt es dann zwei Varianten:
>
> ByVal Wert As int32 ' als zu übergebender Wert
> ByRef Wert As int32 ' als zu übergebender Wert per Referenz
>
> Für Pointer müßte dann immer
> **ByVal** Pointer As IntPtr ' als zu übergebender Wert per Pointer
> gelten?
Ja, auch das geht. Alternativen für Pointer-Übergaben sind also:
- ByVal IntPtr
- ByVal Verweistyp
- ByRef Wertetyp
--
Armin
Mir ist etwas aufgefallen:
Ich bin nicht mehr so sicher, ob man mit
DeviceIoControl
den Pfad zu einem USBStor findet.
Irgendwie sind die unter
http://msdn.microsoft.com/en-us/library/aa365730(v=VS.85).aspx
beschriebenen Funktionen verdächtig.
zB: FindFirstVolumeMountPoint
Retrieves the name of a mounted folder on the specified volume.
FindFirstVolumeMountPoint is used to begin scanning
the mounted folders on a volume.
Zum weiteren Suchen gibt es dazu
FindNextVolumeMountPoint
Continues a mounted folder search started by a call to the
FindFirstVolumeMountPoint function.
FindNextVolumeMountPoint finds one mounted folder per call.
Vielleicht liefert die Funktion nur Keys aus der Registry
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\CPC\LocalMOF
wie eben F:\Hama\CF\, F:\Hama\SD\ oder F:\Hama\XD\?
Eigentlich bräuchte ich die Umkehrung dazu.
Aber welche kommt für mein Ansinnen in Frage?
GetVolumeNameForVolumeMountPoint ?
GetVolumePathName ?
GetVolumePathNamesForVolumeName ?
Doch nirgends kann ich einen Zusammenhang zur VID, PID, Seriennummer finden.
Aber irgendwie muß es ja gehen, denn die Anzeige der Pfade zu gemounteten
Sticks
wird in der Zuordnung zum USB-Lauferk
(das hat ja eine PHYSICALDRIVE-Nummer wie zB.
"Festplatte Modell Generic USB CF Reader USB Device (=PHYSICALDRIVE9)")
und die wird ja im Rahmen der Datenträgerverwaltung in der Form
"Datenträger 9" angezeigt.
Das entspricht exakt der PHYSICALDRIVE-Nummer PHYSICALDRIVE9!
Also müßte der Zusammenhang über die PHYSICALDRIVE-Nummer möglich sein.
Und die Ermittlung der PHYSICALDRIVE-Nummer schließt die Ermittlung von PID,
VID, Seriennummer ein. Das kann ich schon, wenn auch mittels WMI.
Vielleicht geht es aber damit und den Funktionen wie
GetVolumeNameForVolumeMountPoint usf.
Abschließend noch eine Frage:
Du hast vielleicht auch so etwas wie einen USB-MultiCardReader.
Meiner von HAMA hat vier Slots.
Die Seriennummern dieser Slots lauten
00000000000006&0
00000000000006&1
00000000000006&2 und
00000000000006&3
Die Zahl nach "&" scheint eine "Subzahl" zur Seriennummer zu sein.
Wahrscheinlich lautet die Seriennummer des CardReaders selbst
00000000000006, ohne "Subzahl".
Weißt Du eventuell etwas dazu?
Mit bestem Dank im Voraus
Wolfgang
"Armin Zingler" <az.n...@freenet.de> wrote in message
news:8tenbn...@mid.uni-berlin.de...
> Am 05.03.2011 07:10, schrieb Wolfgang Badura:
> Einfach nur "As Long". Da die Elemente Alternativen sind,
> kannst du auch nur den LONGLONG-Part beachten, und der
> ist "64-bit signed integer" wie hier geschrieben:
> http://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx
>
> Oder alternativ:
>
> <StructLayout(LayoutKind.Explicit)> _
> Structure LargeInteger
> <FieldOffset(0)> Public LowPart As Integer
> <FieldOffset(4)> Public HighPart As Integer
> <FieldOffset(0)> Public QuadPart As Long
> End Structure
>
> Fertige Deklarationen findest du auch hier:
> http://pinvoke.net
>
> Ich würde mich aber nicht immer drauf verlassen! Also kopieren,
> um Tipparbeit zu sparen, dann aber nochmal prüfen.
>
> Bei LARGE_INTEGER gibt's keine für VB:
> http://pinvoke.net/default.aspx/Structures.LargeInteger
Danke!
>
>
>> Dann noch eine grundsätzliche Frage:
>>
>> Strukturen, Tabellen sind doch Verweistypen.
>
> Strukturen (Structures) sind _Wertetypen_.
> Bei Tabellen weiß ich nicht, welche du meinst. Klassen
> sind Verweistypen.
Ups. Das hatte ich einfach falsch in meiner Erinnerung gespeichert gehabt.
Verzeih!!!!
Doch von solchen Fehlern lernt man das Meiste.
>
>> Wenn ich diese in einem Declare Stmt ansprechen möchte, muß
>> ich **immer** ByRef verwenden.
>
> Wenn ein Pointer auf einen Wertetyp erwartet wird, dann musst
> du ByRef verwenden.
Also das stimmt wenigstens!
>
>> Bei Wertetypen wie zB. für int32 gibt es dann zwei Varianten:
>>
>> ByVal Wert As int32 ' als zu übergebender Wert
>> ByRef Wert As int32 ' als zu übergebender Wert per Referenz
>>
>> Für Pointer müßte dann immer
>> **ByVal** Pointer As IntPtr ' als zu übergebender Wert per Pointer
>> gelten?
>
> Ja, auch das geht. Alternativen für Pointer-Übergaben sind also:
> - ByVal IntPtr
> - ByVal Verweistyp
> - ByRef Wertetyp
Also wirklich falsch lag ich so gar nicht.
Abgesehen von der Panne am Beginn meiner Frage.
Danke,
Wolfgang
Die Funktionen funktionieren schon richtig. :-)
Als Mountpoints bekommst du den Verzeichnisnamen. Beispiel:
Einen USB-Stick habe ich gemountet unter F:\TEST, wobei F:
eine Festplatte ist (genauer: ein Volume auf einer Festplatte).
Wenn ich nun zum Volume, das den Buchstaben F: trägt, die
Mountingpoints ermittle, bekomme ich "TEST\" geliefert.
Als nächsten Schritt kannst du mit GetVolumeNameForVolumeMountPoint
den eindeutigen Volume-Namen des Volumes ermitteln, das unter F:\Test
gemountet ist. Ausgabe aus Test-Programm: (Erklärung unterhalb)
\\?\Volume{ce6b1224-25ad-11e0-99cd-806e6f6e6963}\
Mount points:
#0
Name: test\
Volume name: \\?\Volume{74380397-2747-11e0-a2a1-1c6f654c8b03}\
Volume Information:
Volume name : Archiv
SerialNumber : 00000000
MaxCompLength : 255
FSFlags : CASE_SENSITIVE_SEARCH, CASE_PRESERVED_NAMES, [usw...]
File system name : NTFS
Disk extents:
Anzahl Extents: 1
Extent 0:
Disk # :3
StartingOffset :32.256
ExtentLength :164.694.749.184
Dies sind die Infos zum Volume mit LW-Buchstaben F: auf der Platte.
Mountpoints gibt es einen (#0) mit dem Namen "test\" (also F:\test).
Dieser Mountpoint verweist auf das Volume
"\\?\Volume{74380397-2747-11e0-a2a1-1c6f654c8b03}\" (auf dem USB-Stick)
Für dieses Volume gibt es folgende Infos:
\\?\Volume{74380397-2747-11e0-a2a1-1c6f654c8b03}\
Mount points:
Volume Information:
Volume name : USBSTICK
SerialNumber : 04B0AE3F
MaxCompLength : 255
FSFlags : CASE_PRESERVED_NAMES, UNICODE_ON_DISK
File system name : FAT32
Disk extents:
Anzahl Extents: 1
Extent 0:
Disk # :7
StartingOffset :20.480
ExtentLength :16.038.998.016
Hier werden die "Disk extents" relevant: Das Volume befindet
sich auf dem physikalischen Laufwerk mit Index 7. Und damit
sind wir genau bei dem Punkt, so wie ich es aber schon vor
einigen Tagen schrieb: Es fehlt lediglich eine zuverlässige Aussage
darüber, wie der Index 7 zustande kommt. Es ist dieselbe
Zahl, wie sie auch in der Datenträgerverwaltung angezeigt wird
("Datenträger 7").
Das einzige, was somit fehlt, ist eine Auflistung aller Devices
anhand derer du sowohl die VID/PID als auch den Datenträger-Index
ablesen kannst. Natürlich können wir mittlerweile die VID/PIDs
auflisten aber wir können aus der Liste nicht den benötigten Index
ablesen. Beispiel: Ich habe in der Datenträgerverwaltung acht
Datengräger (0 bis 7). Wenn ich die Device-Interface Class "Disk"
enummeriere bekomme ich zwar acht Einträge, aber nicht in
derselben Reihenfolge, wie sie in der Datenträgerverwaltung
aufgeführt sind. Beispielsweise bekomme ich als erste Disk
die Platte gelistet, die in der Datenträgerverwaltung als
"Datenträger 3" augeführt wird. Ergo, die Indizes stimmen
nicht überein. Und nur an dieser bekloppten Auflistung
scheitert es bisher.
> Eigentlich bräuchte ich die Umkehrung dazu.
>
> Aber welche kommt für mein Ansinnen in Frage?
> GetVolumeNameForVolumeMountPoint ?
> GetVolumePathName ?
> GetVolumePathNamesForVolumeName ?
>
> Doch nirgends kann ich einen Zusammenhang zur VID, PID, Seriennummer finden.
>
> Aber irgendwie muß es ja gehen, denn die Anzeige der Pfade zu gemounteten
> Sticks
> wird in der Zuordnung zum USB-Lauferk
> (das hat ja eine PHYSICALDRIVE-Nummer wie zB.
> "Festplatte Modell Generic USB CF Reader USB Device (=PHYSICALDRIVE9)")
> und die wird ja im Rahmen der Datenträgerverwaltung in der Form
> "Datenträger 9" angezeigt.
> Das entspricht exakt der PHYSICALDRIVE-Nummer PHYSICALDRIVE9!
> Also müßte der Zusammenhang über die PHYSICALDRIVE-Nummer möglich sein.
> Und die Ermittlung der PHYSICALDRIVE-Nummer schließt die Ermittlung von PID,
> VID, Seriennummer ein. Das kann ich schon, wenn auch mittels WMI.
>
> Vielleicht geht es aber damit und den Funktionen wie
> GetVolumeNameForVolumeMountPoint usf.
Genau.
> Abschließend noch eine Frage:
> Du hast vielleicht auch so etwas wie einen USB-MultiCardReader.
> [...]
> Weißt Du eventuell etwas dazu?
Nö.
--
Armin
In diesem Fall musst du
\\?\Volume{ce6b1224-25ad-11e0-99cd-806e6f6e6963}\test\
an GetVolumeNameForVolumeMountPoint übergeben damit
\\?\Volume{74380397-2747-11e0-a2a1-1c6f654c8b03}\
zurückgegeben wird.
--
Armin
Also geht es doch!
Ene Lösung scheint in Sicht.
Habe Deinen Code schon teilweise eingebaut, aber nicht vollständig
und wegen div Fehler noch auskommentiert.
Wolfgang