HID-Device in Windows identifizieren



  • Hallo Leute,

    ich habe von meinem Prof. ein Projekt bekommen, indem wenn ich es starte alle meine angeschlossenen USB-Devices in einem separaten Logwindow erscheinen.
    Dort sieht man dann ca. folgendes :

    "Device \?\hid#vid_16c0&pid_1001&mi_01#7&37a49a66&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} can be opened for R/W
    VID: 16c0, PID 1001, Revision: 0"

    Meine Aufgabe war es mir zu überlegen, welche Informationen man benötigt damit man zwei Identische (z.b.) Platinen mit denselben VID,PID, Revision und Interfaces noch genauer und eindeutig unterscheiden kann.

    Er ruft die Funktion mit einem "wchar_t *path" auf und ich finde die Definition von path nicht. Daher weiss ich nicht was genau der hintere Ausdruck bedeutet also der:
    "#7&37a49a66&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"

    Anscheinend unterscheidet windows nochmal anhand einiger Daten jedes Gerät spezifisch. Z.b. die 32-bit Zahl "37a49a66".

    Kann mir bitte einer helfen udn sagen worin windwos die unterschiede macht und was für Datentypen das sind? (am besten an meinem Beispiel). Umso mehr Infos umso besser!

    Danke für die HIlfe. Bin ausserdem noch ein Programmieranfänger.

    Gruß
    Markus



  • Zu diesem Zwecke hat man die Seriennummer erfunden, die Du ganz einfach per HidD_GetSerialNumberString ermitteln kannst.

    Allerdings vergeben Schlampen keine Seriennummern, wie in Deinem Fall. Damit kannst Du Platinen ganz einfach nicht eindeutig identifizieren. Windows behilft sich, in dem es die Geräte den Ports zuweist, an die sie angeschlossen sind und eine eigene eindeutige Nummer verteilt (das Zeugs, das Du hinter der Interface-Nummer (mi_01) siehst). Für Dich bleibt nur der String, den Du in Deinem Log-Window siehst. Noch eindeutiger bekommst Du es nicht hin.

    Es lebe der Massenspeicher: Hier schreibt die Spezifikation eine Seriennummer vor und legt sogar noch das Format fest. Da wär Dir das in dieser Form nicht passiert.



  • Okay das mit der Seriennummer stimmt. Die erkennt meiner wirklich nicht was extrem blöd ist.

    Habe in der Zwischenzeit herausgefunden wie ich mir alle USB-Devices mit einem existierenden Programm "USBDeview" anschaun kann und mir bissal weiterhilft beim Suchen.
    Mit einer weiteren Stunde googlen habe ich dann auch diese Seiten bei MSDN gefunden:

    "http://msdn.microsoft.com/de-de/library/windows/apps/dn263091.aspx"
    "http://msdn.microsoft.com/de-de/library/windows/hardware/dn303351(v=vs.85).aspx"

    Somit weiß ich jetzt schonmal, dass Windows eine ParentID Prefix definiert für jedes USB-Device "7&37a49a66&0" und das der Ratenschwanz in den KLammern "{4d1e55b2-f16f-11cf-88cb-001111000030}" eine gewisse "winUsbId" sein soll.

    Damit denke ich wird das Gerät unter Windows eindeutig identifierzt.

    Jetzt sind noch 2 Fragen offen:

    Was ist die 0000 vor der geschweiften Klammer?
    Und Wie kann ich mir die ParentID und winUsbId ausgeben lassen wie im Beispiel "VID: 16c0, PID 1001, Revision: 0" somit ich dann "VID: 16c0, PID 1001, Revision: 0, ParentID: XX, winUsbId: YY" stehen habe.

    das ist die Zeile dazu im Quelltext wo das dann ausgegeben wird:

    Funktionsparameter Funktionsname(parameter)
    {
    HIDD_ATTRIBUTES hid_attribs;
    
    ...
    
    logprintf(L"\r\nVID: %x, PID %x, Revision: %d", hid_attribs.VendorID, hid_attribs.ProductID, hid_attribs.VersionNumber);
    
    ...
    }
    

    Muss ich dann eine hid_attribs.ParentID und eine hid_attribs.winUsbId anlegen??

    Bzw wie kann ich für eine Windows Struktur zwei paramter hinzufügen?
    speziell gemeint in der HIDD_ATTRIBUTES-Struktur.

    Vielen Dank weiterhin für Hilfe.
    Bin hier fleißig am googlen und testen :).

    Gruß
    Markus



  • pargus schrieb:

    Okay das mit der Seriennummer stimmt. Die erkennt meiner wirklich nicht was extrem blöd ist.

    Das hat mit erkennen nichts zu tun. Der Hersteller (Van Ooijen Technische Informatica) muss einfach einen entsprechenden String-Decriptor herausgeben, und genau das macht er hier nicht.

    pargus schrieb:

    Damit denke ich wird das Gerät unter Windows eindeutig identifierzt.

    Es geht um den USB-Port, an dem das Gerät hängt, nicht um das Teil selbst. Wenn Du Dein Gerät an einen anderen Anschluss hängst, wird es auch als ein anderes Gerät erkannt. Besonders schön lässt sich das Verhalten bei USB<->RS232 Wandlern beobachten. Haben diese keine Seriennummer, zählt die Port-Nummer hoch, wenn Du das Ding woanders anschließt. Hast Du aber eine Seriennummer, ist auch die Port-Nummer an allen Anschlüßen die gleiche (da ja jetzt das Gerät als solches erkannt wird).

    Ansonsten ist der String "Device \?\hid#vid_16c0&pid_1001&mi_01#7&37a49a66&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}" bereits eindeutig. Diesen gibt es nur ein mal auf Deinem System. Das ist bereits genau das, was Du wissen willst. Das Wissen um die Eltern bringt Dich da überhaupt nicht weiter.



  • Mox schrieb:

    Das hat mit erkennen nichts zu tun. Der Hersteller (Van Ooijen Technische Informatica) muss einfach einen entsprechenden String-Decriptor herausgeben, und genau das macht er hier nicht.

    Ah okay danke.

    Mox schrieb:

    Es geht um den USB-Port, an dem das Gerät hängt, nicht um das Teil selbst. Wenn Du Dein Gerät an einen anderen Anschluss hängst, wird es auch als ein anderes Gerät erkannt. Besonders schön lässt sich das Verhalten bei USB<->RS232 Wandlern beobachten. Haben diese keine Seriennummer, zählt die Port-Nummer hoch, wenn Du das Ding woanders anschließt. Hast Du aber eine Seriennummer, ist auch die Port-Nummer an allen Anschlüßen die gleiche (da ja jetzt das Gerät als solches erkannt wird).

    gut zu wissen!

    Mox schrieb:

    Ansonsten ist der String "Device \?\hid#vid_16c0&pid_1001&mi_01#7&37a49a66&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}" bereits eindeutig. Diesen gibt es nur ein mal auf Deinem System. Das ist bereits genau das, was Du wissen willst. Das Wissen um die Eltern bringt Dich da überhaupt nicht weiter.

    Dass das Gerät damit eindeutig beschrieben ist, ist mir klar.

    zuerst zwei fragen: 1) ich liege schon richtig das "7&37a49a66&0" die ParentID Prefix ist ??
    2) Und "{4d1e55b2-f16f-11cf-88cb-001111000030}" die winusbId ist?

    Mir gehts darum, dass wenn ich mit einer Funktion in C einen scan durchführe und mir ausgeben lassen will welche Devices ich an meinem Pc angeschlossen habe, würde ich bei zwei gleichen Devices (z.b. zwei gleiche platinen) dieselbe VID,PID, REV., und Interface Nr. bekommen. Daher möchte ich mir zudem noch die zwei Identifikationsparamter "7&37a49a66&0" und "{4d1e55b2-f16f-11cf-88cb-001111000030}" auch noch ausgeben lassen. Und dazu weiß ich nicht wie ich vom System gesagt bekommen kann in "C" dass er mir diese ausgibt.

    Ausgabe zur Zeit:
    Device \?\hid#vid_16c0&pid_1001&mi_00#7&25aeb47&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} can be opened for R/W
    VID: 16c0, PID 1001, Revision: 0

    Ausgabe gewünscht:
    VID: 16c0, PID 1001, Revision: 0, Interface: mi_00 (oder nur die Nr. 00), ParentID: 7&37a49a66&0, WinUsbId: 4d1e55b2-f16f-11cf-88cb-001111000030, Status: (der kommt später dran.)

    Meine Funktion zur Ausgabe:

    Funktionsparameter Funktionsname(parameter)
    {
    //Funktionsdeklaration
    HIDD_ATTRIBUTES hid_attribs; 
    
    ...
    
    //Funktionsanwendung
    logprintf(L"\r\nVID: %x, PID %x, Revision: %d", hid_attribs.VendorID, hid_attribs.ProductID, hid_attribs.VersionNumber); 
    
    ...
    
    //Dateninfos
    ...
    h->vid = hid_attribs.VendorID;
    h->pid = hid_attribs.ProductID;
    ...
    }
    

    Nun möchte ich meinen logprintf um 2 einträge erweitern am besten mit:
    hid_attribs.ParentID und hid_attribs.winUsbId

    und analog dazu in Zeile 17:
    h->revision = hid_attribs.ParentID;
    h->revision = hid_attribs.winUsbId;

    da aber die Windows-Funktion "HIDD_ATTRIBUTES" diese beiden Einträge nicht hat sondern nur VID,PID und Versionsnummer, weiß ich nicht wo ich diese zwei Identifikationsparameter mir zuschicken lassen kann vom System und dementsprechend mein logprintf erweitern kann, dass ich diese beiden Informationen zur Geräteidentifikation mir noch dazu ausgeben lassen kann.

    Also zusammenfassend: stimmen die Fragen, Wo hat Windows die Informationen abgespeichert zu ParentID und winUsbiD und wie kann ich diese mir vom System ausgeben lassen.

    Danke für die Hilfe.

    Gruß



  • pargus schrieb:

    zuerst zwei fragen: 1) ich liege schon richtig das "7&37a49a66&0" die ParentID Prefix ist ??

    Es beschreibt zumindest den Pfad zum Gerät, von daher wirst Du damit richtig liegen.

    pargus schrieb:

    1. Und "{4d1e55b2-f16f-11cf-88cb-001111000030}" die winusbId ist?

    Das ist schon möglich. Da ich mir diese Frage noch nie gestellt habe müsste ich mir das auch erst anschauen. Da ich mir die Frage aber noch immer nicht stelle, lasse ich das jetzt einfach mal 😉

    pargus schrieb:

    Mir gehts darum, dass wenn ich mit einer Funktion in C einen scan durchführe und mir ausgeben lassen will welche Devices ich an meinem Pc angeschlossen habe,

    Der String, den Du in den Ring geworfen hast, ist nicht programmatisch ermittelt sondern anderen Ursprungs? Habe ich das richtig verstanden? Wenn ja, dann suchst Du die Funktionen des Setup-APIs, namentlich SetupDiGetClassDevs, SetupDiEnumDeviceInterfaces, SetupDiGetDeviceInterfaceDetail und SetupDiDestroyDeviceInfoList (in dieser Reihenfolge).



  • In meinem Fall lege ich VID, PID, Versionsnummer und Interfaces der Platine selbst fest (bzw mein Prof.), aber es geht allgemein darum die DLL (z.b.) sobald zwei gleiche Platinen angesteckt sind, diese eindeutig voneinander unterscheiden kann (da der USB-Deskriptor ja gleich ist).
    Und man kann sich ja von Windows den kompletten Pfad geben lassen und über die ""HIDD_ATTRIBUTES""-Struktur die VID, PID und Versionsnummer relativ leicht ausgeben lassen.
    Nun ist es anscheinend so, dass man sich Interfacenr., ParentID nummer und WinUsbId nicht so einfach ausgeben lassen kann (also aus dem Pfad irgendwie rauslesen muss).
    Falls jemand weiß wie das genau gemacht wird bitte schreiben.
    (falls das schon das ist was du meintest Mox, sorry habs dann nicht ganz kapiert, wie gesagt bin komplett neu auf dem Gebiet und is alles bissal sehr komplex, am besten mit nem Beispiel. 🙂 )

    ⚠
    Außerdem hätte ich noch folgende Anforderungen an meine Bibliothek und würde gerne Hilfe bei der Umsetzung bekommen, speziell die Umsetzung oder Realisierung in C :
    "use case 1":
    Was will ein Nutzer typischerweise haben?

    1. Geräte einfach finden und öffnen
    2. Reports senden/empfangen

    "use case 2":
    Was will er, wenn das Gerät entfernt wird, während die Anwendung läuft?

    1. Soll das Gerät in der Bibliothek erhalten bleiben, mit einer Meldung "entfernt"?
    2. Soll die Bibliothek selber aktiv werden, wenn ein Gerät (alt,neu) enumeriert wird?
    3. Wie kann das Freigeben eines ggf. blockierten Gerätes sinnvoll umgesetzt werden.

    Vorab Info:
    Ich habe eine Struktur angelegt die die Informationen zu den IN-,Out- und FEATURE-Reports und Vid, Pid, Revision, Interface, und buffer beinhaltet und diese Daten werden bei einem neuanstecken des USB Gerätes in einen freien Tabellenplatz, diese Tabelle wurde auch neu angelegt, eingetragen (d.h. die Tabelle zeigt via Pointer auf die Struktur und speichert somit die Adresse wo die Infos stehen in den einzelnen Tabellenplätzen und gibt nur die Indizes an Anwendungen zurück).

    Also brauch von beiden "use-cases" zu jeder nummer ne Umsetzungsmöglichkeit in C. Hoffe ihr könnt mir helfen.

    Gruß
    Markus



  • pargus schrieb:

    In meinem Fall lege ich VID, PID, Versionsnummer und Interfaces der Platine selbst fest (bzw mein Prof.), aber es geht allgemein darum die DLL (z.b.) sobald zwei gleiche Platinen angesteckt sind, diese eindeutig voneinander unterscheiden kann (da der USB-Deskriptor ja gleich ist).
    Und man kann sich ja von Windows den kompletten Pfad geben lassen

    Genau so ist es. Und der Pfad, den Dir das System gibt, ist eindeutig. Über diesen unterscheidest Du die Geräte von einander -> Problem gelöst!

    Falls dem Anwender Deiner Bibliothek das etwas zu lang und/oder zu kryptisch sein sollte, muss er eben Aliase verteilen. Und wenn Du das nicht dem Anwender überlassen willst, machst Du's Dir eben selbst, vielleicht in dieser Art:

    DefineDosDevice(0, TEXT("MY_COOL_HID1"), TEXT("\\\\?\\hid#vid_16c0&pid_1001&mi_01#7&37a49a66&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"));
    hDevice = CreateFile(TEXT("\\\\.\\MY_COOL_HID1"), ...);
    

    pargus schrieb:

    Nun ist es anscheinend so, dass man sich Interfacenr., ParentID nummer und WinUsbId nicht so einfach ausgeben lassen kann (also aus dem Pfad irgendwie rauslesen muss).

    Das macht rein gar nichts. Der String "\?\hid#vid_16c0&pid_1001&mi_01#7&37a49a66&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}" ist bereits eindeutig, das reicht zur Identifizierung. Alles andere wird dem Anwender sowieso zu schwer. Bis heute kannst Du niemandem den Unterschied zwischen COM1 und COM2 erklären, das wird mit ParentID und WinUsbId nicht einfacher. Also: Gebe den ermittelten Pfad zum Gerät zurück und fertig.

    pargus schrieb:

    Außerdem hätte ich noch folgende Anforderungen an meine Bibliothek und würde gerne Hilfe bei der Umsetzung bekommen, speziell die Umsetzung oder Realisierung in C :
    "use case 1":
    Was will ein Nutzer typischerweise haben?

    1. Geräte einfach finden und öffnen

    Das finden der Geräte erledigst Du per SetupAPI. Die nötigen Funktionen habe ich Dir ja bereits genannt. Das Öffnen geschieht, wie bei allen Geräten, per CreateFile.

    pargus schrieb:

    1. Reports senden/empfangen

    Lesen und schreiben funktioniert, wie bei allen Geräten, per ReadFile und WriteFile. Wenn Du nicht die vorgesehenen Endpunkte verwenden willst, sondern stattdessen die weniger effizienten Setup-Requests über den Endpunkt 0, kannst Du alternativ natürlich auch HidD_GetInputReport und HidD_SetOutputReport nehmen.

    pargus schrieb:

    1. Soll das Gerät in der Bibliothek erhalten bleiben, mit einer Meldung "entfernt"?
    2. Soll die Bibliothek selber aktiv werden, wenn ein Gerät (alt,neu) enumeriert wird?
    3. Wie kann das Freigeben eines ggf. blockierten Gerätes sinnvoll umgesetzt werden.

    Derjenige, der bei Dir das Device-Handle hält, muss über das Ereignis unterrichtet werden und daraufhin eben dieses schließen. Zusätzlich muss der Client unterrichtet werden, damit dieser bei Bedarf sein UI aktualisieren kann.

    pargus schrieb:

    Vorab Info:
    Ich habe eine Struktur angelegt die die Informationen zu den IN-,Out- und FEATURE-Reports und Vid, Pid, Revision, Interface, und buffer beinhaltet und diese Daten werden bei einem neuanstecken des USB Gerätes in einen freien Tabellenplatz, diese Tabelle wurde auch neu angelegt, eingetragen (d.h. die Tabelle zeigt via Pointer auf die Struktur und speichert somit die Adresse wo die Infos stehen in den einzelnen Tabellenplätzen und gibt nur die Indizes an Anwendungen zurück).

    Passiert das Lesen und Schreiben der Struktur im selben Thread, der auch ReadFile und WriteFile aufruft?


Log in to reply