![]() |
IOCTL von C nach Delphi portieren
Ich habe folgenden C Quelltext vorliegen, den ich nach Delphi portieren möchte um die digitalen IO-Ports eines Industrie-Mainboards anzusprechen.
Code:
Wie muss die Umwandlung der IOCTL_SYS Funktionscodes aussehen? Diese müssen ja als CONST in Delphi definiert werden,
#define WDT_DEVICE "\\\\.\\WDT_DEVICE"
#define WDT_DEVICE_NAME L"\\Device\\WDT_DEVICE" #define WDT_DOS_DEVICE_NAME L"\\DosDevices\\WDT_DEVICE" // Device type #define WDT_TYPE 35001 // The IOCTL function codes from 0x800 to 0xFFF are for customer use. #define IOCTL_SYS_WDT_SET_TIMEOUT CTL_CODE(WDT_TYPE, 0x800, METHOD_BUFFERED, FILE_WRITE_ACCESS) #define IOCTL_SYS_WDT_START CTL_CODE(WDT_TYPE, 0x801, METHOD_BUFFERED, FILE_WRITE_ACCESS) #define IOCTL_SYS_WDT_STOP CTL_CODE(WDT_TYPE, 0x802, METHOD_BUFFERED, FILE_WRITE_ACCESS) #define IOCTL_SYS_WDT_RESTART CTL_CODE(WDT_TYPE, 0x803, METHOD_BUFFERED, FILE_WRITE_ACCESS) #define IOCTL_SYS_DIO_READ CTL_CODE(WDT_TYPE, 0x804, METHOD_BUFFERED, FILE_WRITE_ACCESS) #define IOCTL_SYS_DIO_WRITE CTL_CODE(WDT_TYPE, 0x805, METHOD_BUFFERED, FILE_WRITE_ACCESS) aber wir muss das aussehen? Vielleicht so...? Und wie rufe ich die dann auf?
Delphi-Quellcode:
Danke schonmal vorab, für eure Hilfe!
CONST
WDT_DEVICE = '\\.\WDT_DEVICE'; WDT_TYPE = $35001; IOCTL_SYS_DIO_WRITE = $805; |
Re: IOCTL von C nach Delphi portieren
WDT_TYPE = 35001;
Das ist eine Dezimalzahl. CTL_CODE ist ein Makro das ein DWORD per Bitschieben zusammensetzt. METHOD_BUFFERED und FILE_WRITE_ACCESS sind einfache Zahlenkonstanten. Es kommen also einfache Zahlen heraus. Ich bin jetzt gerade zu muede das alles nachzuschlagen und auszurechnen. |
Re: IOCTL von C nach Delphi portieren
Code:
Das entspricht folgendem Delphi-Code
#define CTL_CODE(DeviceType, Function, Method, Access) (
((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) )
Delphi-Quellcode:
Da es in Delphi keine Makros gibt, kannst du den Ausdruck mit dem Taschenrechner ausrechnen und als Konstante
(DeviceType shl 16) or (Access shl 14) or (Function shl 2) or Method
hinschreiben oder du schreibst dir die Funktion CTL_CODE(DeviceType, Function, Method, Access:integer):integer und verwendest statt Konstanten eben Variablen. |
Re: IOCTL von C nach Delphi portieren
WDT_TYPE ist falsch - diese Zahl ist kein hexadezimaler Wert :warn:
CTL_CODE ist ja ein Makro, welches die Angaben zusammenrechnet, dieses kannst du auch selber machen und dann das ergebnis angeben (halt wo wie es bei dir schon aussieht). > Die Rechenformel und Konstanten findest du ja im PSDK. Zitat:
Es sind ja alles nur einfache Konstanten. |
Re: IOCTL von C nach Delphi portieren
Das heißt, es könnte dann so aussehen...
Delphi-Quellcode:
oder hab ich es jetzt voll nicht richtig verstanden?!?!
const
WDT_TYPE = 35001; WDT_DEVICE = '\\.\WDT_DEVICE'; WDT_DEVICE_NAME = '\Device\WDT_DEVICE'; WDT_DOS_DEVICE_NAME = '\DosDevices\WDT_DEVICE'; IOCTL_SYS_DIO_WRITE = (WDT_TYPE shl 16) or (2 shl 14) or ($805 shl 2) or 0; IOCTL_SYS_WDT_STOP = (WDT_TYPE shl 16) or (2 shl 14) or ($802 shl 2) or 0; var Form1: TForm1; DriveHandle: THandle; n: DWord; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); begin DriveHandle := CreateFile('\\.\WDT_DEVICE', GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL OR FILE_FLAG_NO_BUFFERING, 0); if (DriveHandle > 0) then begin DeviceIoControl(DriveHandle, IOCTL_SYS_DIO_WRITE, NIL, sizeof('0xf'), NIL, 0, n, NIL); CloseHandle(DriveHandle); end else begin MessageDlg('Fehler, kein (gültiges) Handle!', mtWarning, [mbOK], 0); end; end; |
Re: IOCTL von C nach Delphi portieren
Die Konstante WDT_DEVICE auch verwenden. Dazu ist sie da.
Der DeviceIoControl Aufruf ist falsch. |
Re: IOCTL von C nach Delphi portieren
Ok, die Konstante hab ich jetzt eingepflegt und der Kompiler mosert und sagt mir:
"Konstantenausdruck verletzt untere grenzen" Steh ehrlich gesagt ein bissl auf'm Schlauch! Hat das mit dem fehlerhaften DeviceIOControl-Aufruf zu tun, den Du meinst? |
Re: IOCTL von C nach Delphi portieren
Das Problem ist das WDT_TYPE Integer und nicht Cardinal ist. Indem man es in eine Hex-Konstante umwandelt wird der Typ der Konstante implizit Cardinal statt Integer. Das sollte die Fehlermeldung erlegen.
Delphi-Quellcode:
Der DeviceIoControl-Aufruf macht ueberhaupt keinen Sinn. Es wird ein Puffer mit Laenge fuer die Eingabedaten und ein Puffer mit Laenge fuer die Ausgabedaten uebergeben. Je nach Aufruf kannn einer oder beide der Puffer nil sein. Das haengt davon ab welchen Befehl (hier IOCTL_SYS_DIO_WRITE) man angibt. Wo keine Daten rein- oder rausgehen da braucht man auch keinen Puffer. Die Angabe dafuer ist aber nil fuer den Pufferzeiger und 0 fuer die Pufferlaenge.
const
WDT_TYPE = $88B9; WDT_DEVICE = '\\.\WDT_DEVICE'; WDT_DEVICE_NAME = '\Device\WDT_DEVICE'; WDT_DOS_DEVICE_NAME = '\DosDevices\WDT_DEVICE'; IOCTL_SYS_DIO_WRITE = (WDT_TYPE shl 16) or (2 shl 14) or ($805 shl 2) or 0; IOCTL_SYS_WDT_STOP = (WDT_TYPE shl 16) or (2 shl 14) or ($802 shl 2) or 0; var Form1: TForm1; DriveHandle: THandle; n: DWORD; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); begin DriveHandle := CreateFile(WDT_DEVICE, GENERIC_READ orGENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_NO_BUFFERING, 0); if DriveHandle <> INVALID_HANLDE_VALUE then begin DeviceIoControl(DriveHandle, IOCTL_SYS_DIO_WRITE, nil, sizeof('0xf'), nil, 0, n, nil); CloseHandle(DriveHandle); end else MessageDlg('Fehler, kein (gültiges) Handle!', mtWarning, [mbOK], 0); end; "nil, sizeof('0xf')" ist aber eine unsinnige Angabe. Es soll etwas geschrieben werden (der Namensbestandteil _WRITE signalisiert das ueberdeutlich), aber es wird kein Puffer angegeben. "sizeof('0xf')" ist ein ebenso unsinniger Ausdruck. Soll das die Laenge des Strings '0xf' sein oder die Groesse eines Pointers? Gib doch mal den originalen C-Aufruf an. |
Re: IOCTL von C nach Delphi portieren
Ok, hier nachfolgend der originale c-aufruf
Code:
Ich danke Dir schon mal für die Mühe, die Du Dir machst mir zu Helfen...
DWORD nReturn;
WDTPARAM cParam; typedef struct tagWDTPARAM { unsigned char timeout; unsigned char data_b; } WDTPARAM, *PWDTPARAM; void CDigitalIODlg::Onwrite() { CHAR pbufio[256]; UCHAR data_b; // TODO: Add your control notification handler code here m_edit1.GetWindowText(pbufio, sizeof(pbufio)); // MessageBox(pbufio,MB_OK); sscanf(pbufio, "%2x", &data_b); ; cParam.data_b = data_b; DeviceIoControl(((CDigitalIOApp*)AfxGetApp())->m_hDIO, IOCTL_SYS_DIO_WRITE, &cParam, sizeof(WDTPARAM), NULL, 0, &nReturn, NULL); // printf("Digital IO Write Successfully. \n"); // } |
Re: IOCTL von C nach Delphi portieren
Wie du davon auf so einen Murks kommst ist mir unverstandlich.
sscanf parst einen String in dem ("%2x") ein Byte als zwei Hexziffern steht. Offensichtlich eine Eingabe des Users, denn der Text wird aus einem Editfeld geholt.
Delphi-Quellcode:
Das habe ich hier mal reingehackt.
type
PWDTPARAM = ^WDTPARAM; WDTPARAM = record timeout: Byte; data_b: Byte; end; var cParam: WDTPARAM; nReturn: DWORD; procedure TForm1.FormWrite(Sender: TObject) begin cParam.data_b := IntToStr('$' + Edit1.Text); DeviceIoControl(hDIO, IOCTL_SYS_DIO_WRITE, @cParam, SizeOf(cParam), nil, 0, nReturn, NULL); end; |
Re: IOCTL von C nach Delphi portieren
Das ganze sieht jetzt so aus, allerdings mosert der kompiler...
Delphi-Quellcode:
Er sagt hier...
type
PWDTPARAM = ^WDTPARAM; WDTPARAM = record timeout: Byte; data_b: Byte; end; const WDT_TYPE = $88B9; //35001; WDT_DEVICE = '\\.\WDT_DEVICE'; WDT_DEVICE_NAME = '\Device\WDT_DEVICE'; WDT_DOS_DEVICE_NAME = '\DosDevices\WDT_DEVICE'; IOCTL_SYS_DIO_WRITE = (WDT_TYPE shl 16) or (2 shl 14) or ($805 shl 2) or 0; IOCTL_SYS_WDT_STOP = (WDT_TYPE shl 16) or (2 shl 14) or ($802 shl 2) or 0; var hDIO: THandle; cParam: WDTPARAM; nReturn: DWORD; procedure TForm1.Button1Click(Sender: TObject); begin hDIO := CreateFile(WDT_DEVICE, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL OR FILE_FLAG_NO_BUFFERING, 0); cParam.data_b := IntToStr('$' + Edit1.Text); DeviceIoControl(hDIO, IOCTL_SYS_DIO_WRITE, @cParam, SizeOf(cParam), nil, 0, nReturn, NULL); end; Zitat:
Delphi-Quellcode:
???? :gruebel:
cParam.data_b := StrToInt('$' + Edit1.Text);
und hier... Zitat:
Wie ich vorhin auf so einen Quatsch gekommen bin, ist mir selber ein Rätsel... Vielleicht liegt es daran, dass mir dieser Bereich noch mehr als neu ist. Nur leider komme ich nicht darum herum. Vorher habe ich die notwendigen Hardware-Zugriffe per USB und dem Zugriff auf eine DLL gelöst, nur müssen wir jetzt leider diese auf dem Mainboard integrierten IO-Ports nutzen und dafür gibt es leider keine DLL oder ähnliches. Es geht alles nur über die Windows-API und die DeviceIOControl-Aufrufe... Leider! |
Re: IOCTL von C nach Delphi portieren
Falsche Funktion benutzt. Es soll StrToInt sein und nicht IntToStr. :oops:
Delphi-Quellcode:
Umzutypen sollte vielleicht auch noetig sein.
cParam.data_b := Byte(StrToInt('$' + Edit1.Text));
Delphi-Quellcode:
Zuviel C in letzter Zeit.
DeviceIoControl(hDIO, IOCTL_SYS_DIO_WRITE, @cParam, SizeOf(cParam), nil, 0, nReturn, nil);
Delphi-Quellcode:
Das forciert den richtigen Typ.
IOCTL_SYS_DIO_WRITE = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($805 shl 2) or 0);
|
Re: IOCTL von C nach Delphi portieren
Strike! Jetzt klappt es. Hab den Hardware-Zugriff auch eben getestet und es funktioniert wie gewünscht! Danke für die tolle Unterstützung! :thumb:
Nachfolgend nochmal der komplette Quellcode, bzw. korrekte Abschnitt:
Delphi-Quellcode:
Falls nochmal Fragen auftreten sollten, kann mir bestimmt wieder geholfen werden! Danke nochmal!
unit Unit1;
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TfrmMain = class(TForm) gboxWatchdog: TGroupBox; gboxIOOperations: TGroupBox; Button1: TButton; Edit1: TEdit; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; type PWDTPARAM = ^WDTPARAM; WDTPARAM = record timeout: Byte; data_b: Byte; end; const WDT_TYPE = $88B9; //35001; WDT_DEVICE = '\\.\WDT_DEVICE'; WDT_DEVICE_NAME = '\Device\WDT_DEVICE'; WDT_DOS_DEVICE_NAME = '\DosDevices\WDT_DEVICE'; IOCTL_SYS_WDT_SET_TIMEOUT = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($800 shl 2) or 0); IOCTL_SYS_WDT_START = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($801 shl 2) or 0); IOCTL_SYS_WDT_STOP = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($802 shl 2) or 0); IOCTL_SYS_WDT_RESTART = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($803 shl 2) or 0); IOCTL_SYS_DIO_READ = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($804 shl 2) or 0); IOCTL_SYS_DIO_WRITE = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($805 shl 2) or 0); var frmMain: TfrmMain; hDIO: THandle; cParam: WDTPARAM; nReturn: DWORD; implementation {$R *.DFM} procedure TfrmMain.Button1Click(Sender: TObject); begin hDIO := CreateFile(WDT_DEVICE, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL OR FILE_FLAG_NO_BUFFERING, 0); if (hDIO > 0) then begin try cParam.data_b := Byte(StrToInt('$' + Edit1.Text)); except cParam.data_b := Byte(StrToInt('$' + '0')); end; DeviceIoControl(hDIO, IOCTL_SYS_DIO_WRITE, @cParam, SizeOf(cParam), nil, 0, nReturn, nil); CloseHandle(hDIO); end else begin MessageDlg('Fehler, kein (gültiges) Handle!', mtWarning, [mbOK], 0); end; end; end. |
Re: IOCTL von C nach Delphi portieren
So ist es sauberer und einfacher.
Delphi-Quellcode:
Lokale Variablen sind besser. Dazu muss dann aber das Element timeout explizit gesetzt werden. Bei globalen Variablen wird es implizit auf 0 gesetzt, aber bei lokalen Variablen ist der Inhalt Zufall.
unit Unit1;
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TfrmMain = class(TForm) gboxWatchdog: TGroupBox; gboxIOOperations: TGroupBox; Button1: TButton; Edit1: TEdit; procedure Button1Click(Sender: TObject); public end; type PWDTPARAM = ^WDTPARAM; WDTPARAM = record timeout: Byte; data_b: Byte; end; const WDT_TYPE = $88B9; //35001; WDT_DEVICE = '\\.\WDT_DEVICE'; WDT_DEVICE_NAME = '\Device\WDT_DEVICE'; WDT_DOS_DEVICE_NAME = '\DosDevices\WDT_DEVICE'; IOCTL_SYS_WDT_SET_TIMEOUT = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($800 shl 2) or 0); IOCTL_SYS_WDT_START = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($801 shl 2) or 0); IOCTL_SYS_WDT_STOP = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($802 shl 2) or 0); IOCTL_SYS_WDT_RESTART = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($803 shl 2) or 0); IOCTL_SYS_DIO_READ = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($804 shl 2) or 0); IOCTL_SYS_DIO_WRITE = DWORD((WDT_TYPE shl 16) or (2 shl 14) or ($805 shl 2) or 0); var frmMain: TfrmMain; implementation {$R *.DFM} procedure TfrmMain.Button1Click(Sender: TObject); var hDIO: THandle; cParam: WDTPARAM; nReturn: DWORD; begin hDIO := CreateFile(WDT_DEVICE, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL OR FILE_FLAG_NO_BUFFERING, 0); if hDIO <> INVALID_HANDLE_VALUE then begin cParam.timeout := 0; cParam.data_b := Byte(StrToIntDef('$' + Edit1.Text, 0)); DeviceIoControl(hDIO, IOCTL_SYS_DIO_WRITE, @cParam, SizeOf(cParam), nil, 0, nReturn, nil); CloseHandle(hDIO); end else begin MessageDlg('Fehler, kein (gültiges) Handle!', mtWarning, [mbOK], 0); end; end; end. |
Re: IOCTL von C nach Delphi portieren
ok, du hast recht! so ist es einfach besser!
Hab mein "kleines" Programm zum Testen jetzt auch so weit zusammen, dass ich den integrierten Watchdog-Timer ansprechen kann. Übers Wochenende geht's dann an die Einbindung in das derzeitige Steuerungsprogramm. Und da es schon Freitag-Mittag ist, wünsch ich Dir / allen anderen schon mal ein schönes Wochenende, mit halbwegs vernünftigem Wetter. Hier regnet es leider nur und wenn man schon so früh im Jahr mit so viel Sonne verwöhnt wird, nervt einen dieses Wetter echt ab! MfG NetSonic |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:26 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz