Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Code läuft in VCL aber nicht in Console (GetThreadContext) (https://www.delphipraxis.net/147577-code-laeuft-vcl-aber-nicht-console-getthreadcontext.html)

Zacherl 11. Feb 2010 21:42


Code läuft in VCL aber nicht in Console (GetThreadContext)
 
Hey,

ich habe hier grade ein sehr seltsames Problem. Folgender simpler Code läuft wunderbar, wenn ich ihn in eine VCL Anwendung einfüge:
Delphi-Quellcode:
procedure TfrmMain.Button1Click(Sender: TObject);
var
  ProcessInfo: TProcessInformation;
  StartupInfo: TStartupInfo;
  Context: TContext;
begin
  FillChar(StartupInfo, SizeOf(TStartupInfo), #0);
  StartupInfo.cb := SizeOf(TStartupInfo);
  if CreateProcess(PChar(ParamStr(0)), '', nil, nil, false, CREATE_SUSPENDED,
    nil, nil, StartupInfo, ProcessInfo) then
  begin
    Context.ContextFlags := CONTEXT_INTEGER;
    if GetThreadContext(ProcessInfo.hThread, Context) then
    begin
      MessageBox(0, 'yeah', '', 0);
    end;
  end;
  TerminateProcess(ProcessInfo.hProcess, 0);
end;
Führe ich exakt den selben Code in einer Konsolenanwendung aus, schlägt GetThreadContext() mit dem Fehler "Zugriff auf einen unzulässigen Speicherbereich" fehl :shock: Hat jemand ne Idee woran das liegen kann?

Viele Grüße
Zacherl

Astat 11. Feb 2010 21:52

Re: Code läuft in VCL aber nicht in Console (GetThreadContex
 
Zitat:

Zitat von Zacherl
Führe ich exakt den selben Code in einer Konsolenanwendung aus, schlägt GetThreadContext() mit dem Fehler "Zugriff auf einen unzulässigen Speicherbereich" fehl

Hallo Zacherl, unter FPC, D7 und D2007 gerade ohne Probleme getestet. Funkt alles tadellos.

D2005???

lg. Astat

Zacherl 11. Feb 2010 22:31

Re: Code läuft in VCL aber nicht in Console (GetThreadContex
 
Ne D2010 .. Die Sache wird immer verwirrender. Ich hatte die Aufrufe in einer Funktion verpackt:
Delphi-Quellcode:
function Blabla();
begin
  // Code mit GetThreadContext
end;

begin
  Blabla;
end.
jetzt habe ich den Code einmal testweise direkt in den Main Begin & End Block geschrieben und voilla es funktioniert :wall: Das kann doch nicht sein ..

Dezipaitor 11. Feb 2010 22:32

Re: Code läuft in VCL aber nicht in Console (GetThreadContex
 
Der erste Parameter von CreateProcess muss in einer Variable zwischengespeichert werden!!

Zacherl 11. Feb 2010 22:39

Re: Code läuft in VCL aber nicht in Console (GetThreadContex
 
Zitat:

Zitat von Dezipaitor
Der erste Parameter von CreateProcess muss in einer Variable zwischengespeichert werden!!

:? Das wusste ich gar nicht. Was macht die API, dass solche Umstände nötig sind?

Edit: Mist es klappt trotzdem nicht. Meine Funktion hat jetzt komplett gar keine Parameter mehr. Einfach der normale Code vom Main Block in die Funktion geschoben. Und wieder führt dies zum besagten Fehler :x Ahja ich habe Win7 64bit. Auf meine VM mit XP funktioniert es auch innerhalb der Funktion.

Dezipaitor 12. Feb 2010 00:20

Re: Code läuft in VCL aber nicht in Console (GetThreadContex
 
Zitat:

Zitat von Zacherl
Zitat:

Zitat von Dezipaitor
Der erste Parameter von CreateProcess muss in einer Variable zwischengespeichert werden!!

:? Das wusste ich gar nicht. Was macht die API, dass solche Umstände nötig sind?

Raymond erklärt es:
http://blogs.msdn.com/oldnewthing/ar...1/9673254.aspx

Zitat:

Edit: Mist es klappt trotzdem nicht. Meine Funktion hat jetzt komplett gar keine Parameter mehr. Einfach der normale Code vom Main Block in die Funktion geschoben. Und wieder führt dies zum besagten Fehler :x Ahja ich habe Win7 64bit. Auf meine VM mit XP funktioniert es auch innerhalb der Funktion.
Probier das mal aus:
http://blog.delphi-jedi.net/2008/04/...in-full-glory/

Astat 12. Feb 2010 08:44

Re: Code läuft in VCL aber nicht in Console (GetThreadContex
 
Zitat:

Zitat von Zacherl
.. Die Sache wird immer verwirrender. Ich hatte die Aufrufe in einer Funktion verpackt:

Habs nochmal in einer Funktion versucht, funkt tadellos!?

Wie siehts denn ohne Debuger aus?

lg. Astat

Win32.API 29. Mai 2010 14:53

Re: Code läuft in VCL aber nicht in Console (GetThreadContex
 
So, ich greife das Ganze hier mal auf.

CreatePrcess() kann ich ausschließen, da es in diesem Zusammenhang nicht benutzt wird. Es liegt definitiv an GetThreadContext().

Beispiel, damit Ihr es testen koennt:
Delphi-Quellcode:
procedure Test();
var
  Context: TContext;
begin
  ZeroMemory(@Context, SizeOf(TContext));
  Context.ContextFlags := CONTEXT_DEBUG_REGISTERS;
  writeln(GetThreadContext(GetCurrentThread(), Context));
end;

var
  Context: TContext;
begin
  ZeroMemory(@Context, SizeOf(TContext));
  Context.ContextFlags := CONTEXT_DEBUG_REGISTERS;
  writeln(GetThreadContext(GetCurrentThread(), Context));

  Test();

  readln;
end.
Ausgabe:
Code:
TRUE
FALSE
Getestet mit der Delphi 2010 Trial.

GetLastError sagt 998: Unzulaessiger Zugriff auf einen Speicherbereich.

Im msdn steht folgendes:
Zitat:

A pointer to a CONTEXT structure that receives the appropriate context of the specified thread. The value of the ContextFlags member of this structure specifies which portions of a thread's context are retrieved. The CONTEXT structure is highly processor specific. Refer to the WinNt.h header file for processor-specific definitions of this structures and any alignment requirements.
Das würde es in meinen Augen auch erklären. ABER beide sind 4 Byte-Aligned. Und da Delphi nur 32bit Executables erzeugen kann sollte dass doch passen, oder?

Main: Context: _CONTEXT $411E44
Procedure: Context: _CONTEXT $18FEA8

Wenn ich den Speicher dynamisch anfordere funktioniert das Ganze (Ausgabe: TRUE);

Delphi-Quellcode:
procedure Test_Dynamic();
var
  Context: PContext;
begin
  GetMem(Context, SizeOf(TContext)); //Context: PContext ebx : $20CCD10
  ZeroMemory(Context, SizeOf(TContext));
  writeln(GetThreadContext(GetCurrentThread(), Context^));
end;
Ich würde mich nur ungerne darauf verlassen, dass es nur funktioniert, wenn der Speicher dynamisch angefordert wird.

Was mir spontan ins Auge springt, ist das Alignment. Es ist immer 8 Byte, wenn es funktioniert (0x18FEA8 und 0x20CCD10). Ich kann mich aber auch nicht drauf verlassen, dass Delphi mir mit GetMem einen Speicherblock liefert, der auf 8 Byte Aligned ist.

Ich habe den Gedanken mal weiter verfolgt und was soll ich sagen, es stimmt. GetThreadContext() verlangt einen Speicherblock, der auf 8 Byte-Aligned ist. (Ja, ich beseitzt einen 64bit Prozessor + passendes OS)

Um auf Nummer sicher zu gehen sollte man den Speicher mit so einer Krücke reservieren:
Delphi-Quellcode:
function Get8ByteAlignedContext(): PContext;
begin
  GetMem(result, SizeOf(TContext) + 8);
  while ((DWord(result) mod 8) <> 0) do
    result := Pointer(DWord(result) + 1);
end;
AHHRG: Kommando zurueck! Ich sehe gerade, dass Context in der Main _NICHT_ 8 Byte Aligned war, sondern 4. Und es funktioniert trotzdem. (Wenn man testet dann auch richtig, und nicht nur 8Byte und ungerade Aligments...)

Halten wir also Fest:

Context muss 4Byte-Aligned seinen:
Delphi-Quellcode:
procedure Test_Alignment();
var
  Context: PContext;
  i: Integer;
begin
  GetMem(Context, SizeOf(TContext) * 2);
  ZeroMemory(Context, SizeOf(TContext) * 2);
  for i := 0 to 12 do
  begin
    ZeroMemory(Context, SizeOf(TContext));
    if ((DWord(Context) mod 4) = 0) then
      write('[Aligned] ')
    else
      write('[Not Aligned] ');
    writeln(GetThreadContext(GetCurrentThread(), Context^));
    Context := Pointer(DWord(Context) + 1);
  end;
end;
Code:
[Aligned] TRUE
[Not Aligned] FALSE
[Not Aligned] FALSE
[Not Aligned] FALSE
[Aligned] TRUE
[Not Aligned] FALSE
[Not Aligned] FALSE
[Not Aligned] FALSE
[Aligned] TRUE
[Not Aligned] FALSE
[Not Aligned] FALSE
[Not Aligned] FALSE
[Aligned] TRUE
Aber wieso Funktioniert der Aufruf im Main Abschnitt und in der Funktion nicht?

Wenn sich jemand durch die "Wall-of-Text" gekaempft hat, danke schon mal dafuer. Bin fuer alle Ideen und Anregungen offen.

Grüße,
Win32.API

himitsu 29. Mai 2010 15:10

Re: Code läuft in VCL aber nicht in Console (GetThreadContex
 
Der Delphi-Speichermanager und vorallem FastMM reserviert eigentlich nur 8-Byte-Aligned-Speicherblöcke.
Er wurde extra darauf hin ausgelegt.

Also kann der erhaltene Speicherblock (z.B. via GetMem) direkt verwendet werden.

Zacherl 29. Mai 2010 15:16

Re: Code läuft in VCL aber nicht in Console (GetThreadContex
 
Hey Danke dir für deine Analyse. Hatte nicht damit gerechnet, dass sich nochmal jemand zu dem Thema meldet :mrgreen: Habe bisher leider auch keine weiteren Informationen sammeln können. Scheint dann tatsächlich ein Bug im MemoryManager zu sein :?

@himitsu: Wie es scheint wird in der Subfunktion ja grade kein 8-Byte-aligned Block reserviert.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:39 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz