WriteFile liefert immer ERROR_INVALID_PARAMETER
-
An unterschiedlichen Projekt-Einstellungen liegt es ziemlich sicher nicht. Die Funktion innerhalb der Dll wird doch scheinbar korrekt aufgerufen. Und da sich alle folgenden Aktionen innerhalb dieser einen Dll abspielen, sollte das kein Problem sein.
Allerdings fällt mir folgendes auf:
daimonion schrieb:
WriteHandle = CreateFile((DetailedInterfaceDataStructure->DevicePath), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); ErrorStatus = GetLastError(); if(ErrorStatus == ERROR_SUCCESS) { ReadHandle = CreateFile((DetailedInterfaceDataStructure->DevicePath), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); ErrorStatus = GetLastError(); } if (ErrorStatus == ERROR_SUCCESS) { DWORD BytesWritten = 0; unsigned char OutputPacketBuffer[65]; //Allocate a memory buffer equal to our endpoint size + 1 //Lese-/Schreibe Daten OutputPacketBuffer[0] = 0; OutputPacketBuffer[1] = 0x82; //Kommando um alle Eingänge zu lesen //Prüfe ob auch geschrieben wurde if (!WriteFile(WriteHandle, &OutputPacketBuffer, 65, &BytesWritten, 0)) { ErrorStatus = GetLastError(); //Fehler beim Schreiben. Beende dich selbst. SetupDiDestroyDeviceInfoList(hDevInfo); return false; } }
-
GetLastError liefert den Code des letzten Errors. Wenn aber kein Fehler passiert ist, ist der Wert nicht aussagekräftig. Der Wert kann auch der Fehlercode einer ganz anderen Funktion sein, die irgendwann einmal in die Hose gegangen ist.
-
Wenn WriteFile in die Hose geht, schließt Du die frisch geöffneten HANDLEs nicht.
-
Beim Aufruf von WriteFile würde ich mir das "&" beim OutputPacketBuffer sparen.
Also so:
WriteHandle = CreateFile((DetailedInterfaceDataStructure->DevicePath), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); ErrorStatus = (WriteHandle == INVALID_HANDLE_VALUE) ? GetLastError() : ERROR_SUCCESS; if(ErrorStatus == ERROR_SUCCESS) { ReadHandle = CreateFile((DetailedInterfaceDataStructure->DevicePath), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); ErrorStatus = (ReadHandle == INVALID_HANDLE_VALUE) ? GetLastError() : ERROR_SUCCESS; } if (ErrorStatus == ERROR_SUCCESS) { DWORD BytesWritten = 0; unsigned char OutputPacketBuffer[65]; //Allocate a memory buffer equal to our endpoint size + 1 //Lese-/Schreibe Daten OutputPacketBuffer[0] = 0; OutputPacketBuffer[1] = 0x82; //Kommando um alle Eingänge zu lesen //Prüfe ob auch geschrieben wurde if (!WriteFile(WriteHandle, OutputPacketBuffer, 65, &BytesWritten, 0)) { ErrorStatus = GetLastError(); //Fehler beim Schreiben. Beende dich selbst. CloseHandle(ReadHandle); CloseHandle(WriteHandle); SetupDiDestroyDeviceInfoList(hDevInfo); return false; } }
Das eigentliche Problem wird sich dadurch sicherlich noch nicht beheben lassen. Auch kann ich nicht erkennen, was hier schief laufen könnte. Das Problem wird wohl eher woanders liegen, nicht in dem gezeigten Code. Da müssten wir erstmal die ganze Pracht ansehen können. Vielleicht sieht man dann, was schief laufen kann.
BTW: Warum öffnest Du das Device gleich zwei mal? Warum reicht Dir nicht ein CreateFile, dafür aber mit Schreib- und Lesezugriff? Und über was für ein Gerät reden wir hier eigentlich, nach welchem Interface lässt Du das SetupApi suchen?
-
-
Hi, und Danke für die Antwort.
Der Code so wie ich ihn gepostet habe ist bei weitem nicht komplett. So viele Fehlermöglichkeiten wie da noch nicht abgefangen sind...
Nein, ich hab erst mal ein grobes Gerüst erstellt um zu schauen ob meine Idee funktioniert. Und na ja schon bei dem Gerüst bin ich gescheitert. Deswegen wende ich mich ja an euch.Ich möchte mal deine Punkte abarbeiten, um die Fragestruktur aufrecht zu erhalten.
1.) Das GetLastError einen anderen Fehler abrufen könnte ist aber durchaus nicht schön. Werde mal meinen Code so anpassen, dass das nicht mehr passieren kann.
2.) Der Code wird momentan nur gedebuggt. Später müssen die Handles natürlich wieder geschlossen werden, was sie definitiv auch tun werden.
3.) Hab ich eigentlich nur so übernommen, wie es in dem Beispiel war. In der MSDN steht es ja auch so drin. Nichtsdestotrotz hab ich das & weg gemacht. Passt mir eigentlich auch besser so.
Leider ist das Verhalten damit noch nicht behoben.
Ich werde mal ein Packet zusammenschnüren, welches ich euch dann hier posten kann.
Was ich versuche zu machen:
Ich hab einen PIC18F2550 mit dem ich via USB kommunizieren will. Auf PIC Seite ist soweit alles fertig. Auf PC Seite möchte ich nun eine DLL schreiben die ich in verschiedene Programme einbinden kann und von da aus mit wenigen Funktionen auf den PIC zugreifen kann. Als ich das PIC Programm geschrieben hab, hab ich mir eine Testsoftware für den PC geschrieben, die nach wie vor einwandfrei funktioniert! Aus dieser hab ich dann meine Codeschnipsel genommen um meine DLL aufzubauen. Selber code der einmal funktioniert und einmal nicht.
Im Endeffekt sind die Funktionen in der DLL spartansich:
init();
getInput();
getOutput();
setOutput();
usw.Die Probleme spielen sich derzeit in der init() Funktion ab die ich aus einer neuen Testapplikation aufrufe (Form mit zwei Buttons, die die jeweiligen DLL-Funktionen aufrufen)!
Noch was hab ich bemerkt. In meiner Testfunktion ( bool test() {...} ) hab ich die Variablendeklaration OutputPacketBuffer[65] aus dem Lokalen in den globalen DLL Bereich (Headerfile) verschoben und dann funktionierte WriteFile. Das könnte aber wiederrum an dem & liegen.
Edit:
So hier erst mal eine URL zu dem Testprogramm, welches ich während des programmieren des PICs geschrieben hab.
DownloadSo und hier mal die URL zu der DLL und einer kleinen Applikation, die die DLL-Funktion aufruft. Dieser Code funktioniert insoweit das Handles aufgebaut werden. WriteFile wirft aber den Fehler ERROR_INVALID_PARAMETER.
Download
-
Aha, es geht hier also um ein HID. Wie sieht denn der Report-Descriptor aus? Mich interessiert da vor allem der Output-Report.
-
BTW: Was in aller Welt soll denn die Funktion getOutput() erledigen?
-
Der Pic hat ja digitale Ein- und Ausgänge. Mit getOutput kann man sich den Zustand des Ausganges holen (0 oder 1) So braucht man in einer übergeordneten Applikation nicht alle I/Os mitführen und synchronisieren.
Report Descriptoren. Soweit wie ich das richtig verstanden hab, nutzt Microchip die gar nicht und soll auf 0 gesetzt werden. Das ist doch immer der erste Arrayindex im Buffer oder? Ich such mal die Unterlage von MC raus.
Edit:
Kommentar aus dem Beispiel von PIC:OutputPacketBuffer[0] = 0; //The first byte is the "Report ID" and does not get transmitted over the USB bus. Always set = 0.
Edit:
Okay, Report Descriptoren sind was anderesIch schau mal wo in meinem Code da was geschrieben steht. Brauchte die bisher nämlich nicht.
-
daimonion schrieb:
Der Pic hat ja digitale Ein- und Ausgänge. Mit getOutput kann man sich den Zustand des Ausganges holen (0 oder 1) So braucht man in einer übergeordneten Applikation nicht alle I/Os mitführen und synchronisieren.
Ach so, das ergibt natürlich Sinn. Ich hatte das eben auf den Report reduziert. Und da ein Output-Report grundsätzlich vom Host in den Controller gereicht wird und niemals anders herum (Einbahnstrasse), sah das auf den ersten Blick etwas putzig aus.
daimonion schrieb:
Report Descriptoren. Soweit wie ich das richtig verstanden hab, nutzt Microchip die gar nicht und soll auf 0 gesetzt werden.
Das erste Byte ist der Report-Identifier. Ob der nun benutzt wird oder nicht, ergibt sich aus dem Descriptor. Unter anderem deswegen wollte ich mir das Dingens anschauen.
Den Descriptor selber muss es aber geben. Ohne dem funktioniert das HID nämlich nicht. Wenn Du den Descriptor eben nicht finden kannst, prüfe wenigstens, ob die Größe von OutputPacketBuffer mit der benötigten Größe des Reports übereinstimmt (HIDP_CAPS.OutputReportByteLength, HidP_GetCaps).
daimonion schrieb:
Das ist doch immer der erste Arrayindex im Buffer oder? Ich such mal die Unterlage von MC raus.
Mit dem MC hat das nichts zu tun, da wirst Du im Datenblatt nichts finden. :p
-
Moin Moin schrieb:
Den Descriptor selber muss es aber geben. Ohne dem funktioniert das HID nämlich nicht. Wenn Du den Descriptor eben nicht finden kannst, prüfe wenigstens, ob die Größe von OutputPacketBuffer mit der benötigten Größe des Reports übereinstimmt (HIDP_CAPS.OutputReportByteLength, HidP_GetCaps).
Ich denke mir der Descriptor wird irgendwie durch die setupapi-Funktionen bzw. Rückwirkend durch CreateFile genutzt. Du hast ja eigentlich den kompletten Code da. Mehr hab ich da auch erst mal nicht. Ich werde mich mal informieren, welchen ReportDescriptor die MC Leute für dieses Beispiel nutzen, bzw. werd mal deine genannten Funktionen probieren, um an Infos zu kommen!
Edit: Wer stellt denn den Descriptor zur Verfügung? Das HID-Device?
EditEdit: HidP_GetCaps ist doch im WDK drin. Soweit ich das hier Überblicke, ist das in meinem VS2005 nicht drin, und runterladen geht nicht da ich bisher noch keinen Account bei MSDN hab...
-
daimonion schrieb:
Ich denke mir der Descriptor wird irgendwie durch die setupapi-Funktionen bzw. Rückwirkend durch CreateFile genutzt.
Das ist so nicht ganz richtig, denn weder CreateFile nocht die SetupAPI-Funktionen interessieren sich für die Reports. Es interessiert sich viel mehr der Treiber direkt dafür. Mit diesen Informationen ist er nämlich in der Lage, Buffer in der richtigen Größe zu allokieren. Das nächste Mal wird es interessant, wenn Du ReadFile und/oder WriteFile aufrufst. Beim Schreiben kann geschaut werden, ob es den angegebenen Report überhaupt gibt. Beim Lesen wird geschaut, welchen Report Du haben möchtest.
Außerdem gibt es noch einen ganzen Haufen Funktionen, um Reports zu parsen oder Daten aus diesen zu extrahieren oder Daten zu setzen.
daimonion schrieb:
Du hast ja eigentlich den kompletten Code da. Mehr hab ich da auch erst mal nicht.
Hier funktioniert Dein Code. Allerdings hätte ich einiges anders gemacht, aber das wollen wir besser nicht diskutieren.
daimonion schrieb:
Ich werde mich mal informieren, welchen ReportDescriptor die MC Leute für dieses Beispiel nutzen, bzw. werd mal deine genannten Funktionen probieren, um an Infos zu kommen!
Du wirst doch mehr als ein Hex-File haben, oder? Da wird doch irgendwo eine Datei zwischen sein, die "descriptors.c" oder so ähnlich heißt. Oder nicht?
daimonion schrieb:
Edit: Wer stellt denn den Descriptor zur Verfügung? Das HID-Device?
Jawoll. Das macht das Device, um den Host mitzuteilen, wie er mit dem Device umzugehen hat.
daimonion schrieb:
EditEdit: HidP_GetCaps ist doch im WDK drin. Soweit ich das hier Überblicke, ist das in meinem VS2005 nicht drin, und runterladen geht nicht da ich bisher noch keinen Account bei MSDN hab...
Ich habe das eben nicht im Blick (ich bin MSDN Kunde), aber es muss doch eine Möglichkeit geben, da einigermaßen blasenfrei heranzukommen. Ohne dem bist Du doch aufgeschmissen. Du kommst doch so nichtmal an Feature-Reports heran, Du kannst Strings nicht lesen, usw..
Aber immerhin weiß ich jetzt, warum Du Dich so mühsam durch die Registry quälst...
-
Okay, dann fangen wir mal an.
Ne bin kein MSDN Kunde. Wär vielleicht mal interessant, wenn wir hier in Zukunft öfters so was machen. Kostet das was?
Klar hab ich mehr als das Hex File. Da sieht man mal wieder, das ich noch nicht wirklich viel Ahnung von USB und HID habe. Der Report Deskriptor (bzw. ein Auszug aus dem File) folgt weiter unten.
Hier funktioniert Dein Code. Allerdings hätte ich einiges anders gemacht, aber das wollen wir besser nicht diskutieren.
Ich bin über jede Kritik erfreut. Wenn sie negativ ist, dann hab ich wenigstens was zum lernen. Ist manchmal nicht einfach aus dem nichts alles zu begreifen.
So, zurück zum Problem. Ich hab hier eine "usb_descriptor.c":
usb_descriptor.cSo wie ich das sehe, passt das da drin soweit alles so zusammen, wie auch im C++ Code. Hoffe es hilft.
Besten Dank schon mal für deine Hilfe! Hast nen Kasten Bier gut.
Grüße
Daimonion
-
daimonion schrieb:
Ne bin kein MSDN Kunde. Wär vielleicht mal interessant, wenn wir hier in Zukunft öfters so was machen. Kostet das was?
Ja, doch, man kann schon sagen, dass das was kostet:
http://download.microsoft.com/download/4/1/0/4100640B-A19F-4278-9CC3-09BD9B713111/Compare%20MSDN%20and%20Expression%20Subscriptions.pdfAber wenn ich das richtig sehe, bekommst Du das WDK auch über die Connect - Seiten. Es kann gut sein, dass es hier mit einer Anmeldung getan ist. Ich hab's jetzt aber nicht probiert.
daimonion schrieb:
So, zurück zum Problem. Ich hab hier eine "usb_descriptor.c":
Das Byte-Array ganz am Ende der Datei ist der Report-Descriptor. Auch wenn das nicht gerade ein typischer Report für Joysticks ist, sehe ich da auch keine Besonderheiten. Er passt jedenfalls zu dem, was Du da machst.
Ich sehe eben jedenfalls keinen Grund warum das nicht funktionieren soll. Und in der Tat funktioniert das bei mir auch. Ich habe lediglich VID und PID und die Größe des Reports angepasst, damit es sich mit dem von mir angeschlossenen HID verträgt. Beim Durchsteppen kann ich klar sehen, dass WriteFile mit TRUE zurückkommt (die Funktion returned, ohne das die Handles freigegeben werden und ohne den Aufruf von SetupDiDestroyDeviceInfoList
).
Probiert habe ich das mit dem Projekt "Joysticktester", zusammen mit "USB Joystick DLL".
Eben bin ich ehrlich gesagt auch einigermaßen ideenlos, sorry.
BTW: Was passiert, wenn Du die 4 Zeilen mit dem Kommentar "// Usage Minimum ..." und "// Usage Maximum..." im Report auskommentierst?
-
Herje, wenn das bei dir Funktioniert, dann weiß ich auch nicht mehr weiter...
Momentan bau ich die DLL so um, dass ich keine CLR mehr brauche. Also reines C++ mit std. Sobald ich das getan habe, werde ich nochmal ein anderes Testprogramm in Delphi schreiben und nochmal berichten!
Das Byte-Array ganz am Ende der Datei ist der Report-Descriptor. Auch wenn das nicht gerade ein typischer Report für Joysticks ist, sehe ich da auch keine Besonderheiten. Er passt jedenfalls zu dem, was Du da machst.
Der Report ist aus einer HID Generic Demo. Daher wahrscheinlich auch der recht allgemeine Report.
Danke dir auf jeden Fall für deine Hilfe!
Daimonion
-
-
Jap bin ich. Nur bin ich da nicht so aktiv.
-
So, jetzt hab ich nochmal den ganzen clr Kram aus der DLL rausgehauen und mich nur auf C++ verlassen. Weiterhin hab ich das dll Projekt nochmal neu angelegt und den Code nochmal neu eingefügt. Jetzt scheint alles zu funktioninieren!
Danke an die/den Helfer
Grüße
DaimonionEdit:
Funtkionierte doch nicht. Aber dann ist mir aufgefallen das ich meine Indexvariable für die setupapi zu zeitig inkrementiert hatte. Seitdem dieser Fehler korrigiert ist, funktionierts wirklich.