Entwickler-Ecke

Windows API - dynamischer Buffer für API-Calls


retnyg - Fr 06.05.05 16:18
Titel: dynamischer Buffer für API-Calls
Zitat:

Delphi-Quelltext
1:
2:
function ReadFile(hFile: THandle; var Buffer; nNumberOfBytesToRead: DWORD;
  var lpNumberOfBytesRead: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;

buffer ist normalerweise ein statischer array of char, wie kann ich hier einen dynamischen array erstellen, der von der funktion "geschluckt" wird ?
geht weder mit nem string und setlength noch mit getmem...
hier meine bisherigen versuche:

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:
function xgetfilesize(f:dword):dword; register;
asm
   push FILE_END
   push 0
   push 0
   push eax
   call SetFilePointer
end;

function ReadTextfile(filename:string):string;register;
type charr=array of char;
var f: Thandle;
    fs:int64;
    p:^charr;
begin
    f:=CreateFile(@filename[1],GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
    if f <> INVALID_HANDLE_VALUE then begin
       fs:=xGetFileSize(f);
//       getmem(p,fs+1);
//       setlength(p,fs+1);
       p:=AllocMem(fs+1);
       //fillchar(p^,fs+1,#0);
       //initialize(p,fs+1);
       setlength(result,fs+1);
       readfile(cardinal(f),p,fs,0,0);
{       asm
       push 0
       push 0
       push fs
       push p^
       push f
       call ReadFile
       end; }

       closehandle(f);
       copymemory(@result[1],p,fs+1);
       freemem(p);
       //freemem(p,fs+1);
//       finalize(p);
    end;
end;


uall@ogc - Fr 06.05.05 16:21

meinst sowas:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var p: pointer;
    read: cardinal;
begin
  getmem(p,100);
  //...
  ReadFile(hFile,p^,read,nil);
  //...


retnyg - Fr 06.05.05 16:28

wenn ich das genauso mache

Delphi-Quelltext
1:
       readfile(f,p^,fs,0,nil);                    

kriege ich hier nen fehler: die typen der formalen und tatsächlichen parameter müssen übereinstimmen
edit: das mit den typen lag am read...
ich bekomm aber immer noch nix gescheites ins result


delfiphan - Fr 06.05.05 16:41

Dynamisches array of char: Übergib einfach MyArray[0].
Bei Strings: SetLength, danach Pointer(MyString)^ übergeben (bzw. PChar(MyString)^; aber nach SetLength ist ja klar, dass der String nicht leer ist, demnach ist hier kein Compiler-Magic nötig).


retnyg - Fr 06.05.05 18:32

danke für die tips, so müsste es ja eigentlich funktionieren:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
function ReadTextfile(filename:string):string;register;
const BUFSIZE = 4096;
type charr=array of char;
var f: Thandle;
    fs:dword;
    i:integer;
    p:^charr;
    dwRead:DWORD;
    //p:^charr;
begin
    f:=CreateFile(pchar(filename),GENERIC_READ,FILE_SHARE_READ or FILE_SHARE_WRITE,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
    if f <> INVALID_HANDLE_VALUE then begin
       fs:=xGetFileSize(f);
       setlength(result,fs+1);
//       cardinal(p):=GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT, fs+1);
       fillchar(pointer(result)^,fs+1,#0);
       readfile(f,pointer(result)^,fs,dwRead,nil);
//       showmessage(syserrormessage(GEtlasterror));
       closehandle(f);
       if dwread <> 0 then showmessage(result);
    end;
end;

readfile wird zwar mit EAX = 1, also true, beendet, aber dwRead ist immer 0 :shock:


retnyg - Fr 06.05.05 18:52

hat sich erledigt, solange ich den filepointer rumschiebe ist ja eigentlich logisch dass read immer null bleibt :autsch:


delfiphan - Fr 06.05.05 18:59

Lag es nicht am xgetfilesize? Ohne diese Funktion geht's bei mir.


retnyg - Fr 06.05.05 19:10

ja, daran lag es... :lol:


delfiphan - Fr 06.05.05 19:17

Ah, jetzt komm ich nach, was du meintest mit "filepointer rumschieben"... Übrigens: SetLength(Result, fs) reicht aus (+1 nicht nötig). Die Strings (AnsiString) sind intern immer nullterminiert berechnet, damit man jederzeit ohne Umrechnung per PChar(MyString) einen nullterminierten String erhalten kann.

Mir ist bewusst, dass du das wahrscheinlich noch tun wirst aber damit keine halbfertige Funktion im Forum rumliegt: Der Fall wo die zu lesende Datei 0 Bytes gross ist müsste man noch separat behandeln.


retnyg - Fr 06.05.05 20:06

also hier das korrigierte resultat:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
function ReadTextfile(filename:string):string;register;
var f: Thandle;
    fs:dword;
    dwRead:DWORD;
begin
    result:='';
    f:=CreateFile(@filename[1],GENERIC_READ,FILE_SHARE_READ or FILE_SHARE_WRITE,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
    if f <> INVALID_HANDLE_VALUE then begin
       fs:=GetFileSize(f,nil);
       if fs <> 0 then begin
         setlength(result,fs);
         readfile(f,pointer(result)^,fs,dwRead,nil);
       end;
       closehandle(f);
    end;
end;

sollte ziemlich schnell sein, verglichen mit readln usw.