Einzelnen Beitrag anzeigen

Win32.API

Registriert seit: 23. Mai 2005
312 Beiträge
 
#8

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

  Alt 29. Mai 2010, 15:53
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
  Mit Zitat antworten Zitat