Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas? (https://www.delphipraxis.net/107816-readfileex-writefileex-verwenden-fehler-windows-pas.html)

EConvertError 2. Feb 2008 17:16


ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Hallo!

Beim Versuch dieses Beispiel in eine Delphi-Komponente zu packen, stoße ich schon wieder auf ein Problem.

Ich brauche diese beiden Funktionen (aus dem MSDN kopiert):
Code:
BOOL WINAPI WriteFileEx(
  __in     HANDLE hFile,
  __in_opt LPCVOID lpBuffer,
  __in     DWORD nNumberOfBytesToWrite,
  __inout  LPOVERLAPPED lpOverlapped,
  __in_opt LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
Code:
BOOL WINAPI ReadFileEx(
  __in      HANDLE hFile,
  __out_opt LPVOID lpBuffer,
  __in      DWORD nNumberOfBytesToRead,
  __inout   LPOVERLAPPED lpOverlapped,
  __in_opt  LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
Delphi-Quellcode:
type
  // TODO: Use classes here in the future (if possible)
  PPipeInstance = ^TPipeInstance;
  TPipeInstance = record
    Overlapped: TOverlapped;
    PipeHandle: THandle;
    chRequest: array[1..BUFSIZE] of Char;
    cbRead: DWord;
    chReply: array[1..BUFSIZE] of Char;
    cbToWrite: DWord;
  end;
...
var
  PPipeInst: PPipeInstance;
  AWrite: Boolean;
...
WriteFileEx(PPipeInst^.PipeHandle, @PPipeInst^.chReply[1], PPipeInst^.cbToWrite, POverlapped(PPipeInst), CompletedWriteMethod);
POverlapped(PPipeInst) schluckt er nicht, weil Delphi ein TOverlapped (_OVERLAPPED) verlangt:
Zitat:

[Pascal Fehler] NamedPipeServer.pas(70): E2010 Inkompatible Typen: '_OVERLAPPED' und 'POverlapped'
MSDN sagt aber eindeutig:
Zitat:

A pointer to an OVERLAPPED data structure...
Jetzt vermute ich einen Fehler in der Windows.pas, weshalb ich dort auch schon TOverlapped in POverlapped geändert habe. Nur schluckt er meinen Code noch immer nicht...
Wo muss man das ändern und ist das auch wirklich ein Fehler in Delphi?

Danke,
Andreas

PS: Bei ReadFileEx() verlangt Delphi wie erwartet ein POverlapped.

Christian Seehase 2. Feb 2008 17:24

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Moin Andreas,

Zitat:

Zitat von EConvertError
Jetzt vermute ich einen Fehler in der Windows.pas, weshalb ich dort auch schon TOverlapped in POverlapped geändert habe.

hast Du die Windows.pas auch neu compiliert? (und vor allem: Vor der Änderung gesichert?)
Wenn nicht, wird immer die alte Unit verwendet.

Also in den Fällen, in denen ich mit mitgelieferten Deklarationen nicht klarkomme, importiere ich mir die Funktionen lieber selbst (statt in den VCL-Sourcen zu ändern)
Das macht dann auch die eventuelle Weitergabe von Sourcen einfacher, da jemand anderes dann nicht auf geänderte Originaldateien angewiesen ist (was jemand, der z.B., eine PE hat auch gar nicht machen könnte.)

Dezipaitor 2. Feb 2008 18:17

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Du übergibst doch eindeutig deine eigene Struktur PPipeInst, wo POVERLAPPED verlangt ist.

Ich vermute, dass du eigentlich folgendes nutzen wolltest:

Delphi-Quellcode:
WriteFileEx(PPipeInst^.PipeHandle, @PPipeInst^.chReply[1], PPipeInst^.cbToWrite, PPipeInst.Overlapped, CompletedWriteMethod);
Edit:
Habe mir die Funktion angeschaut. Es müsste eigentlich ein Pointer auf OVERLAPPED sein.
Die JEDI-API exportiert es korrekt. Sogar in D2007 ist ein ein CONST.

Ich persönlich ziehe die JEDI Implementation vor.

EConvertError 2. Feb 2008 18:45

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Zitat:

hast Du die Windows.pas auch neu compiliert? (und vor allem: Vor der Änderung gesichert?)
Wie kompiliert man die neu? DCU-Löschen hat es nicht getan....

Klar, habe ich vor den Änderungen gesichert. ;-) Wobei das ist nicht mehr so wichtig, weil ich mir die Funktionen auch noch mal selbst eingebunden habe. So gesehen bräuchte ich auch die JEDI-Header nicht mehr...

Zitat:

Du übergibst doch eindeutig deine eigene Struktur PPipeInst, wo POVERLAPPED verlangt ist.
Jupp, ist auch volle Absicht. ;-) Ein PPipeInstance kann man auf POverlapped casten, während man ein POverlapped nicht auf ein TOverlapped casten kann. In der MSDN-Vorlage (siehe Link oben) wird das auch gemacht. Wenn man das MSDN-Beispiel kompiliert funktioniert die Geschichte zumindest. Mal sehen ob ich das auch hinbekomme. :gruebel:

Anscheinend braucht man gar kein gültiges TOverlapped-Record, was bedeutet, dass ich auch einen Pointer auf ein Objekt (mein zukünftiges threadsicheres TNamedPipeClient) übergeben könnte. Das wollte ich mit dem Kommentar "Use classes here in the future" andeuten.

Mal sehen, ob sich meine Speicherzugriffsverletzung in Luft auflöst, oder ob es da noch ein Problem gibt...

Danke,
Andreas

PS: D2007 importiert es richtig? D.h. ich könnte da ein IFDEF einbauen?

DGL-luke 2. Feb 2008 19:12

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
ja, bei D2006 ist es ein const, d.h. ein impliziter pointer. da kannst du aber wieder keinen eigenen Pointer übergeben.

Dezipaitor 2. Feb 2008 19:32

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Es kann kein CONST sein. Es ist laut Definition ein In/Out Wert, was entweder ein Pointer sein muss oder VAR.

---

Sorry, das Beispiel habe ich übersehen.
Aber darf ich fragen, ob du es verstanden hast? Das Beispiel ist doch sehr typisch für C und damit imho trickreich.

EConvertError 2. Feb 2008 19:56

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Ja, doch so im Großen und Ganzen verstehe ich doch sehr gut, was die da tun.

Ich bekomme schon die Anfrage des Clients richtig rein. Die Antwort funktioniert noch nicht ganz (bekomme immer '?????' statt 'This is a test reply!'). Die Lösung wird wohl in der Verwendung der richtigen String-Sorte sein...

Die Callbacks funktionieren auch ganz gut, dank des MakeProcInstance-Tricks... ;-)

Andreas

DGL-luke 2. Feb 2008 19:57

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
bei D2006 IST es ein const. (upsa, ich hab ja gar kein D2007)

PS: const bedeutet pass-by-reference, genauso wie var und out. und es gibt bei diesen drei schlüsselwörtern in delphi keinen unterschied außer der sie repräsentierenden zeichenfolge.
EDIT: Und der Compiler weigert sich, die neuzuweisung eines const-params zu übersetzen. naja.

EConvertError 2. Feb 2008 20:04

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Ja, Delphi 2006 (Turbo Edition) verwende ich auch. ;-)

Mir ist schon klar, was const bedeutet. Aber ich brauche es als Pointer, um diesen C-Trick nachmachen zu können. ;-) Und POverlapped ist sicher "korrekter" (weil sinngemäßer) übersetzt.

Ja, wie gesagt mein letztes Problem ist nur mehr, dass ich die Anfrage in ein Array of Char einlese. Da bekomme ich 't',#0,'e',#0,'s',#0,'#0','t',#0 (Der Rest des Buffers natürlich mit #0 gefüllt.). Zurückgesendet wird zurzeit ohne #0 dazwischen, was dann natürlich nicht gut funktioniert ('?????').

Der Client ist (zur Zeit noch!) nicht von mir... ;-)
Sonst könnte ich es ja auch anders einlesen.

Grüße,
Andreas

DGL-luke 2. Feb 2008 20:09

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
das ist dann wohl unicode...

Dezipaitor 2. Feb 2008 20:16

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Zitat:

Zitat von DGL-luke
PS: const bedeutet pass-by-reference, genauso wie var und out. und es gibt bei diesen drei schlüsselwörtern in delphi keinen unterschied außer der sie repräsentierenden zeichenfolge.
EDIT: Und der Compiler weigert sich, die neuzuweisung eines const-params zu übersetzen. naja.

Dein Edit ist ja der Unterschied. Der Delphi Compiler macht den Unterschied zwischen den Aufrufkonventionen.

Aber dass Windows.pas hier einfach ein Datentypentyp, statt einem Zeiger auf den Datentyp verwendet finde ich schon sehr falsch. Es mag zwar funktionieren, jedoch nicht in allen Fällen, wie man sieht.

Ich sehe grad übrigens, dass TPipeInstance falsch übersetzt ist. Die Arrays müssen strenggenommen von 0 bis BUFSIZE-1 gehen.



Zitat:

Zitat von EConvertError
Ja, doch so im Großen und Ganzen verstehe ich doch sehr gut, was die da tun.

Ich meine nicht, was du tust, sondern was das Beispiel micht. Ehrlich gesagt, musste ich auch erst ein paar mal lesen, um es zu verstehen.
Die erweitern den record TOverlaped, indem sie ihn als LPPIPEINST neu deklarieren. Das macht man indem man einfach den vorhanden Record an die erste Stelle im neuen Record setzt. Das ist (fast) so, als ob man einfach die Inhalte des Overlapped records in den neuen an den Anfang kopiert. Jede Funktion, die ein Zeiger auf ein Overlapped-Record erwartet, arbeitet dann mit dieser struktur fein. Den Rest im Record verwenden die Callbackfunktionen für eigene Zwecke.


Die Nullen jedes zweite Byte deuten scharf auf Unicode hin. Du musst es natürlich der Gegenseite gerecht machen und dies erkennen.

EConvertError 2. Feb 2008 20:34

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Zitat:

Aber dass Windows.pas hier einfach ein Datentypentyp, statt einem Zeiger auf den Datentyp verwendet finde ich schon sehr falsch.
Vor allem machen es die Codegearler nur bei einer von den beiden Funktionen.

Zitat:

Ich sehe grad übrigens, dass TPipeInstance falsch übersetzt ist. Die Arrays müssen strenggenommen von 0 bis BUFSIZE-1 gehen.
Von 1 bis BUFSIZE ist nicht in Ordnung?

Ähm...nein, dass die den Record so erweitern ist mir nicht so wirklich aufgefallen. ;-) :oops:
Ich habe einfach meinen eigenen Record genommen und es scheint zu funktionieren. Wobei ich mir dann die Frage stelle: Hat das nur zufällig funktioniert?
Hat es etwa nur funktioniert, weil das TOverlapped an erster Stelle steht im Record? Soll heißen, ich kann keinen Pointer auf ein Objekt übergeben und mein eigenes TNamedPipeClient-Objekt verwenden?

Die Antwort habe ich schon richtig hinbekommen. *freu* Ich werde jetzt allerdings sicher nicht allzu viel Energie hineinstecken, da mir sowieso eine eigene TStream-Klasse (TNamedPipeStream oder so 8) ) für die Kommunikation vorschwebt. Dann kann man alles was das Herz begehrt hin und herjagen. :mrgreen:

Anderas

Dezipaitor 2. Feb 2008 22:34

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Die Arraygrenzen sind hier weniger von bedeutung, da sie wohl garnicht genutzt werden. Aber in C fangen Arrays immer mit 0 an.

Die Recorderweiterung ist manchmal doch nützlich in C. Ist so ähnlich wie bei Vererbung. Aber nur entfernt :D

himitsu 9. Feb 2008 18:41

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
nja, CONST ist eigentlich kein Problem (selbst bei In/Out-Vars), denn schließlich wird hier ja nur der Recordinhalt geändert und nicht der Speicherplatz dieser Variable.


PS: leider hat Delphi zu oft derartige Definitionsprobleme :cry:

falsche Parametertypen (Vorzugsweise falsche ANSI-Parameter in Unicode-Funktionen)
oder eben VAR/CONST statt POINTER.

Code:
function ReadFile(hFile: THandle; var Buffer; nNumberOfBytesToRead: DWORD;
  [color=#ff0000]var lpNumberOfBytesRead: DWORD;[/color] lpOverlapped: POverlapped): BOOL; stdcall;
versucht hier mal ein NIL (also nichts) als lpNumberOfBytesRead zu verwenden :wall:


die einfachste Lösung ist da natürlich gleich auf externe Header/Definitionen zurückzugreifen (z.B. JEDI) ... außerdem bekommt man so auch "neuerer" Definitionen, welche in Delphi noch immer nicht eingeflossen sind.

Dezipaitor 9. Feb 2008 18:54

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Ich kann einfach nur JEDI API Lib empfehlen.
Und wenn Ihr ein Fehler findet, so setzt euch mit den Entwicklern oder mir in Kontakt. Wir sind immer glücklich, wenn Fehler gefunden werden.

EConvertError 10. Feb 2008 15:37

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Natürlich verwende ich die JEDI API Lib für größere Dinge (btw: großes Lob dafür). Aber zwei Funktionen kann man sich auch selbst mal einbinden. ;-)

Die ganze Geschichte funktioniert bereits, ich muss allerdings noch testen, ob man anstatt des Records auch eine Klasse verwenden kann. Ich werde euch da Bescheid geben (kann allerdings eine Weile dauern, weil ich immer im Stress bin ;-) ).

Danke,
Andreas

Dezipaitor 10. Feb 2008 21:53

Re: ReadFileEx/WriteFileEx verwenden: Fehler in Windows.pas?
 
Eine Klasse wirst du wohl Streamen müssen.

Ich verwende ausschließlich JwaWindows als Unit. Einfacher gehts nimmer. Okay man darf dann nicht auf die EXE-Größe achten. Aber selbst dann kann man die JEDI Units noch einzeln verwenden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:48 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