Ich verweise hier nochmal auf das Alignment bzw. die Enum Typ Größe. Mit den entsprechenden Compiler Switches funktionieren bei mir folgende Varianten problemlos:
Delphi-Quellcode:
var
ReturnLength: ULONG;
begin
// Deklaration als PULONG
NtQueryObject(x, x, x, x, @ReturnLength);
// Deklaration als var ULONG
NtQueryObject(x, x, x, x, ReturnLength);
Ich kann mich irren, aber soweit ich weiß, interpretiert Delphi einen OUT Parameter genauso wie einen VAR Parameter. Sprich, wenn du, wie in deinem Beispiel ReturnLength als OUT PULONG deklarierst, ist das dann der Pointer auf den Pointer auf ReturnLength und nicht nur der Pointer auf ReturnLength.
Außerdem: Wenn du ReturnLength lokal als PULONG deklarierst, dann zeigt dieser Pointer entweder ins Leere (auf 0) oder wird mit einem Zufallswert initialisiert. Ruftst du dann die
API auf und übergibst die Variable direkt, dann wird natürlich versucht die Rückgabelänge in einen invaliden Speicherbereich zu schreiben.
Wenn du ReturnLength aber als ULONG deklarierst und dann @ReturnLength übergibst, zeigt der Pointer auf die korrekt adressierte lokale Variable.
Zur Verdeutlichung:
Delphi-Quellcode:
var
ReturnLength: ULONG;
pReturnLength: PULONG;
begin
// Wir gehen von einer ReturnLength deklaration als PULONG aus
// FALSCH:
// pReturnLength ist hier ein uninitialisierter Pointer.
// die API versucht die Länge zu schreiben, indem sie dereferenziert: pReturnLength^ := Länge
// da der Pointer aber auf einen undefinierten Speicherbereich zeigt, bekomst du eine AV
NtQueryObject(x, x, x, x, pReturnLength);
// RICHTIG:
// der Speicher von ReturnLength wurde von Delphi korrekt alloziiert
// wir übergeben die Referenz auf diesen Speicher, also den Pointer, der auf ReturnLength zeigt
NtQueryObject(x, x, x, x, @ReturnLength);
Das Problem mit der Übergabe von Length = 0 kann ich ebenfalls nicht nachvollziehen. Der Aufruf von
NtQueryObject(x, x, nil, 0, x)
funktioniert für mich wunderbar. Aber vermutlich rührt dieses Problem von deiner fehlerhaften Implementation der ReturnLength her.