Entwickler-Ecke
Windows API - DeviceIoControl - Von C zu Delphi / PPJoy
drasir - Di 19.12.06 19:35
Titel: DeviceIoControl - Von C zu Delphi / PPJoy
Hi,
ich würde gern mitt "PPJoy" von meinem Programm aus Joystickdaten an Windows geben. Das Programm bietet dafür eine Schnittstelle via "DeviceIOcontrol".
Leider gibt es dazu nur C-SampleCode. Kann mir jemand weiterhelfen?
Das wichtigste folgendes:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| #pragma pack(push,1) /* All fields in structure must be byte aligned. */ typedef struct { unsigned long Signature; /* Signature to identify packet to PPJoy IOCTL */ char NumAnalog; /* Num of analog values we pass */ long Analog[NUM_ANALOG]; /* Analog input values */ char NumDigital; /* Number of digital values we pass */ char Digital[NUM_DIGITAL]; /* Digital input values */ } JOYSTICK_STATE; #pragma pack(pop) |
Wie sieht die Structur in Delphi aus?
Seh ich das richtig das:
Quelltext
1: 2:
| HANDLE h; h= CreateFile("\\\\.\\PPJoyIOCTL1",GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL); |
In Delphi einfach:
Delphi-Quelltext
1: 2: 3:
| Var H:Thandle; ... h:=CreateFile("\\\\.\\PPJoyIOCTL1",GENERIC_WRITE,FILE_SHARE_WRITE,nil,OPEN_EXISTING,0,nil); |
ist?
Unter
http://www.geocities.com/deonvdw/PPJoy.htm -> Supported Interfaces -> Virtual Joystick -> Sample
findet man auch ein komplettes C-Program.
Moderiert von
raziel: Delphi-Tags hinzugefügt
wulfskin - Di 19.12.06 20:02
Hallo,
wie wärs denn mit ausprobieren? ;)
Aber sieht auf den ersten Blick gut aus, ein struct übersetzt du dann mit einem (packed) record.
Gruß Hape!
drasir - Di 19.12.06 20:15
Aha, auf das "packed" wär ich schon NIE gekommen :)
Also so?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| Type JoyStruct = packed record Signature:longint; NumAnalog: char; Analog: array of longint; NumDigital: char; Digital: array of char; end; |
Mit den Arrays bin ich mir nicht so sicher...
Ist
long Analog[NUM_ANALOG]; =
Analog: array of longint; oder wie?
Moderiert von
raziel: Delphi-Tags hinzugefügt
wulfskin - Di 19.12.06 20:32
Ja fast, so ist es richtig ;):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| TJoyStickState = packed record Signature: Cardinal; NumAnalog: Byte; Analog: Array [0..NUM_ANALOG] of Integer; NumDigital: Byte; Digital: Array [0..NUM_DIGITAL] of Byte; end; |
Übrigens, bei dem
packed bin ich mir nicht so sicher!
Gruß Hape!
drasir - Di 19.12.06 20:38
So gibt das auch viel mehr Sinn :)
Danke schonmal bis hier!
Was mir jetzt noch Kopfzerbrechen bereitet:
Delphi-Quelltext
1:
| #define JOYSTICK_STATE_V1 0x53544143 |
das wär unter Delphi $53544143 ?
und
Quelltext
1: 2: 3: 4:
| #define PPORTJOY_IOCTL(_index_) \ CTL_CODE (FILE_DEVICE_PPORTJOY, _index_, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_PPORTJOY_SET_STATE PPORTJOY_IOCTL (0x0) |
Ich brauche IOCTL_PPORTJOY_SET_STATE für den DeviceIOControl Aufruf...
Moderiert von
raziel: Delphi-Tags hinzugefügt
wulfskin - Di 19.12.06 23:33
Hallo,
da erste stimmt soweit.
Das zweite kenne ich leider auch nicht, sieht aber nach einem Macro aus. Aber da gibt es noch andere Spezialisten, die dir da sicherlich weiterhelfen können!
Gruß Hape!
drasir - Mi 20.12.06 11:08
Dann hoffe ich mal das besagte Experten meinen Thread sehen :)
Deine Posts haben mir aber auch schon sehr weitergeholfen! Danke!
BenBE - Mi 20.12.06 19:21
drasir hat folgendes geschrieben: |
Quelltext 1: 2: 3: 4:
| #define PPORTJOY_IOCTL(_index_) \ CTL_CODE (FILE_DEVICE_PPORTJOY, _index_, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_PPORTJOY_SET_STATE PPORTJOY_IOCTL (0x0) |
Ich brauche IOCTL_PPORTJOY_SET_STATE für den DeviceIOControl Aufruf...
Moderiert von raziel: Delphi-Tags hinzugefügt |
Laut Dokumentation des PSDK sieht das CTL_CODE-Makro so aus:
Quelltext
1: 2: 3:
| #define CTL_CODE( DeviceType, Function, Method, Access ) ( \ ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ ) |
Mit den dazugehörigen Definitionen:
Quelltext
1: 2: 3: 4:
| #define METHOD_BUFFERED 0 #define METHOD_IN_DIRECT 1 #define METHOD_OUT_DIRECT 2 #define METHOD_NEITHER 3 |
Sowie den Zugriffsrechten:
Quelltext
1: 2: 3: 4:
| #define FILE_ANY_ACCESS 0 #define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) #define FILE_READ_ACCESS ( 0x0001 ) // file & pipe #define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe |
Übersetzt sich das ganze einfach durch entsprechende Left-Shifts um die angegebene Anzahl an Bits.
Sollte also etwa so hier (vereinfacht) aussehen:
Delphi-Quelltext
1: 2:
| const IOCTL_PPORTJOY_SET_STATE = FILE_DEVICE_PPORTJOY shl 16 + _index_ shl 2; |
drasir - Mi 20.12.06 21:12
Super! Werde das gleich morgen ausprobieren!
Btw. mit dem Handy finde ich es jetzt nicht, aber wie mach ich die Delphi-Code Tags?
drasir - Do 21.12.06 13:03
Hm also ich habe jetzt folgendes:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33:
| Type TJSS = packed record Signature: Cardinal; NumAnalog: Byte; Analog: Array [0..8] of Integer; NumDigital: Byte; Digital: Array [0..16] of Byte; end;
var Form1: TForm1; joy:tjss; H:Thandle; ret:longbool; rsize:dword;
Const _index = $0; JoyStick_State_V1 = $53544143; FILE_DEVICE_UNKNOWN = $00000022; IOCTL_PPORTJOY_SET_STATE = FILE_DEVICE_UNKNOWN shl 16 + _index shl 2; ...
procedure TForm1.Button1Click(Sender: TObject); var c:poverlapped; d:cardinal; begin h:=CreateFile('\\\\.\\PPJoyIOCTL1',GENERIC_WRITE,FILE_SHARE_WRITE,nil,OPEN_EXISTING,0,0); joy.Signature:=Joystick_State_V1; joy.NumAnalog:=8; joy.Analog[1]:=100; joy.NumDigital:=16; joy.Digital[1]:=1; ret:=DeviceIoControl(h,IOCTL_PPORTJOY_SET_STATE,@joy,sizeof(joy),nil,0,d,nil); closehandle(h); |
Leider passiert da genau nichts...
BenBE - Do 21.12.06 16:17
drasir hat folgendes geschrieben: |
Hm also ich habe jetzt folgendes:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33:
| Type TJSS = packed record Signature: Cardinal; NumAnalog: Byte; Analog: Array [0..8] of Integer; NumDigital: Byte; Digital: Array [0..16] of Byte; end;
var Form1: TForm1; joy:tjss; H:Thandle; ret:longbool; rsize:dword;
Const _index = $0; JoyStick_State_V1 = $53544143; FILE_DEVICE_UNKNOWN = $00000022; IOCTL_PPORTJOY_SET_STATE = FILE_DEVICE_UNKNOWN shl 16 + _index shl 2; ...
procedure TForm1.Button1Click(Sender: TObject); var c:poverlapped; d:cardinal; begin h:=CreateFile('\\\\.\\PPJoyIOCTL1',GENERIC_WRITE,FILE_SHARE_WRITE,nil,OPEN_EXISTING,0,0); joy.Signature:=Joystick_State_V1; joy.NumAnalog:=8; joy.Analog[1]:=100; joy.NumDigital:=16; joy.Digital[1]:=1; ret:=DeviceIoControl(h,IOCTL_PPORTJOY_SET_STATE,@joy,sizeof(joy),nil,0,d,nil); closehandle(h); |
Leider passiert da genau nichts... |
Man beachte die von mir markierten Stellen ...
Das _index war nur für dich, um zu zeigen, wo Du die 0x0 aus dem Makro einsetzen solltest ...
Delphi-Quelltext
1:
| IOCTL_PPORTJOY_SET_STATE = FILE_DEVICE_PPORTJOY shl 16 + $0 shl 2; |
Das
FILE_DEVICE_PPORTJOY hatte schon seine Berechtigung: Diese Konstante müsste bei Dir irgendwo in den Headern deklariert sein; kann sie im MSDN nicht finden.
Und zu guter Letzt eine kleine Einführung in C-Strings ;-)
Die Zeichenfolge
'\\' in C heißt so viel wie Ich will hier nen
\ haben. Das ist in C notwendig, da ein einfacher \ in einem C-String ein Escape-Zeichen ist. Ferner steht das
'\\\\.\\PPJoyIOCTL'L hinter dem String für Unicode. Wäre die korrekte Übersetzung des Strings also
'\\.\PPJoyIOCTL'
drasir - Do 21.12.06 17:40
Das mit dem Index ist mir dann auch aufgefallen... Allerdings sollte die Deklaration mit "_index = $0" doch "0x0" entsprechen oder?
Das FILE_DEVICE_PPORTJOY ist im c-Header so deklariert:
[C]
#define FILE_DEVICE_PPORTJOY FILE_DEVICE_UNKNOWN
[/C]
Ich bin deshalb davon ausgegangen das ich auch direkt "FILE_DEVICE_UNKNOWN" benutzen kann.
Den Wert dazu kannte Delphi nicht, habe ihn aber mit ein bisschen googlen als $00000022 identifiziert.
Das mit dem '\\' wusste ich nicht, das 'l' dahinter ist aber eigentlich eine '1' (eins) die die Nummer des virtuellen Joysticks representiert (von 1-16).
Jetzt hab ich also:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| Type TJSS = packed record Signature: Cardinal; NumAnalog: Byte; Analog: Array [0..8] of Integer; NumDigital: Byte; Digital: Array [0..16] of Byte; end;
var Form1: TForm1; joy:tjss; H:Thandle; ret:longbool; rsize:dword;
Const JoyStick_State_V1 = $53544143; FILE_DEVICE_UNKNOWN = $00000022; IOCTL_PPORTJOY_SET_STATE = FILE_DEVICE_UNKNOWN shl 16 + $0 shl 2;
procedure TForm1.Button1Click(Sender: TObject); var c:poverlapped; d:cardinal; a:pjoyinfoex; s:string; begin h:=CreateFile('\\.\PPJoyIOCTL1',GENERIC_WRITE,FILE_SHARE_WRITE,nil,OPEN_EXISTING,0,0); joy.Signature:=Joystick_State_V1; joy.NumAnalog:=8; joy.Analog[1]:=100; joy.NumDigital:=16; joy.Digital[1]:=1; ret:=DeviceIoControl(h,IOCTL_PPORTJOY_SET_STATE,@joy,sizeof(joy),nil,0,d,nil); closehandle(h); end; |
Es geht aber immernoch nicht...
ist denn meine übersetzung von
[c]
DeviceIoControl(h,IOCTL_PPORTJOY_SET_STATE,&JoyState,sizeof(JoyState),NULL,0,&RetSize,NULL)
[/c]
in
Delphi-Quelltext
1:
| DeviceIoControl(h,IOCTL_PPORTJOY_SET_STATE,@joy,sizeof(joy),nil,0,d,nil); |
richtig?
BenBE - Fr 22.12.06 21:01
Fragen wir mal anders: Bekommst Du für H ein gültiges Handle?
Sources: Für C-Sources bitte CS-Tags (C#) nehmen. Reines C kann dieses Forum (noch) nicht ... (Oder wurden die CPP schon umgesetzt (@
Christian S.)???
@PPORTJOY: Aso, solche Dinge immer mit Übersetzen, sonst kommt's nur zu Verwirrungen ... Die VCL-Sources und Header-Übersetzungen der RTL sind u.a. deshalb relativ beschissen, weil sie teilweise nur Schrott übersetzt haben, der für den Normalen Menschen geht, und alles was nicht gebraucht wurde, ignoriert ...
Wenn Du vom C-Source und deinem Delphi-Source n ASM-Listing hast, kannsch Dir sagen, ob's korrekt is *g* (Bitte nur die besagte Routine, mit Zeilenmarkierungen der Originalsources: CPU-Fenster --> Gemischte Anzeige)
gerdich - Mo 13.08.12 22:29
Der Code funktoniert bis auf kleine Fehler ganz gut.
Allerdings darfst Du das Datei-Handle nicht gleich wieder schliessen, sonst ist die Wirkung gleich wieder null. Ein Joystick-Signal im Mikrosekundenbereich ist wirkungslos.
Du solltest das Datei-Handle zu Beginn des Formulars öffnen (create) und beim Beenden (destroy) freigeben. Dann wirst Du sehen, dass alle Joystickbefehle gut ankommen. Ich habe es getestet.
Delete - Di 14.08.12 07:30
Auch wenn Du nagelneu bist: ACHTE IN ZUKUNFT AUF DAS DATUM! -> Letzter Eintrag verfasst: Fr 22.12.06 21:01
gerdich - Di 14.08.12 12:15
Das Datum habe ich schon gesehen.
Der Thread ist aber immer noch im Internet und hat keine Lösung gefunden.
Das Problem ist weiterhin brandaktuell: Sony Sixaxis läuft über ppjoy.
Ich wäre froh gewesen, ich hätte meine Antwort schon vorher im Netz gefunden.
Es hat mich etwas Zeit gekostet das herauszufinden.
Ich wollte noch den Code dazu setzen. Zum Glück habe ich es nicht getan, da sich offensichtlich niemand mehr dafür interessiert.
Narses - Di 14.08.12 13:05
Moin und :welcome: in der EE!
gerdich hat folgendes geschrieben : |
Das Datum habe ich schon gesehen.
Der Thread ist aber immer noch im Internet und hat keine Lösung gefunden. |
Hm, das ist wohl etwas unglücklich gelaufen. :| Ich schätze mal, dass
hathor dich nicht verärgern wollte, sondern einen der hier gelegentlich auftretenden Thread-Archäologen vermutet hat. ;) Da geht´s dann ja nicht um Lösungen, sondern nur um Aufmerksamkeit... :zwinker:
gerdich hat folgendes geschrieben : |
Ich wollte noch den Code dazu setzen. Zum Glück habe ich es nicht getan, da sich offensichtlich niemand mehr dafür interessiert. |
Selbstverständlich sind wir in der EE immer an Lösungen interessiert, auch wenn die Frage schon etwas älter ist. Wenn du also eine Lösung beitragen kannst (und noch möchtest :?), bist du hier bei uns immer herzlichen Willkommen! :beer:
cu
Narses
gerdich - Di 14.08.12 18:07
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109:
| unit main;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type Tioctrl = class(TForm) procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormKeyPress(Sender: TObject; var Key: Char); private public end;
var ioctrl: Tioctrl;
implementation
{$R *.dfm} Const JoyStick_State_V1 = $53544143; pp_joy_axis_min=1; pp_joy_axis_max=32767; FILE_DEVICE_UNKNOWN = 34; set_state=0; method_buffered=0; file_any_access=0; nanalog=8; ndigital=16;
Type TJSS = packed record Signature: Cardinal; NumAnalog: shortint; Analog: packed Array [0..nanalog-1] of Integer; NumDigital: shortint; Digital: packed Array [0..ndigital-1] of shortint; end; var IOCTL_PPORTJOY_STATE: cardinal; joy:tjss; H:Thandle; ret:longbool; rsize:dword;
function ctl_code(device_type:word;access:byte;func:word;method:byte):cardinal; begin result:=device_type; result:=result shl 2; inc(result,access); result:=result shl 12; inc(result,func); result:=result shl 2; inc(result,method) end;
procedure Tioctrl.FormCreate(Sender: TObject); begin h:=CreateFile('\\.\PPJoyIOCTL1',GENERIC_WRITE,FILE_SHARE_WRITE,nil,OPEN_EXISTING,0,0); if h=Invalid_handle_value then caption:='Ladefehler ' else caption:='ok '; end;
procedure Tioctrl.FormClose(Sender: TObject; var Action: TCloseAction); begin closehandle(h) end;
procedure Tioctrl.FormKeyPress(Sender: TObject; var Key: Char); var d:cardinal; rc:cardinal; t:integer; const digitalkey='1234567890qwertz'; analogkey='asdfghjk'; begin joy.Signature:=Joystick_State_V1; joy.NumAnalog:=nanalog; joy.NumDigital:=ndigital; t:=pos(key,digitalkey); if t>0 then joy.Digital[t-1]:=1-joy.Digital[t-1] else begin t:=pos(key,analogkey); if t>0 then if joy.Analog[t-1]=pp_joy_axis_min then joy.Analog[t-1]:=pp_joy_axis_max else joy.Analog[t-1]:=pp_joy_axis_min end; ioctl_pportjoy_state:=ctl_code(FILE_DEVICE_UNKNOWN,file_any_access,set_state,method_buffered); if not DeviceIoControl(h,IOCTL_PPORTJOY_STATE,@joy,sizeof(joy),nil,0,d,nil) then begin rc:=getlasterror; if rc=2 then caption:=caption+'Treiber entfernt' else caption:=caption+'iocontrol-Fehler '+inttostr(rc) end end;
var init_t:integer; initialization begin for init_t:=0 to nanalog-1 do joy.Analog[init_t]:=(pp_joy_axis_max+pp_joy_axis_min)div 2; for init_t:=0 to ndigital-1 do joy.Digital[init_t]:=0 end;
end. |
Man sieht:
Nur wenige kleinere Änderungen:
- C-char entspricht Delphi-shortint (Hier unwichtig, solange keine negativen Werte).
- [0..n] sind n+1 Elemente.
- shl von #0 ist sinnlos.
...
Im Wesentlichen war der Code ganz korrekt. Nur durfte man das Handle nicht gleich wieder schliessen, sonst blieb keine Wirkung zurück.
ppjoy kann jetzt von Delphi aus verwendet werden, um verschiedenste Eingabegeräte (u.a. Midi-controller und Sony sixaxis) einzulesen und damit beliebige Programme zu steuern.
ppjoy erscheint als neuer Joystick.
Mit ppjoy kann man nun auch programmgesteuert auf eine andere Applikation einwirken, die auf Joystick- oder Tastatureingaben (oder anderes wartet). Dazu braucht man nun auch kein Windows-Handle mehr, sondern die Wirkung betrifft alle Applikationen, wie ein Hardware-Joystick, eine Hardware-Maus oder eine Hardwaretastatur.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!