Habe den Code jetzt nochmal etwas genauer debuggt, weil mir dieser CopyAndSkipString einfach absolut unsinnig vorkam und habe wohl recht gehabt. Das Problem liegt an einer komplett anderen Stelle.
RtlInitUnicode String erstellt keinen neuen Buffer für den String, sondern setzt das entsprechende Feld lediglich auf die Adresse des Source Strings. PAnsiChar/PWideChar Stringkonstanten packt Delphi allerdings scheinbar in eine read-only Section der Anwendung, weshalb jedlicher Schreibversuch zu einer
Access Violation führt.
Delphi-Quellcode:
var
Source: PWideChar;
begin
Source := 'TestString';
// Oops, this is read-only memory
Source[1] := 'x';
RtlRunEncodeUnicodeString für seinen Teil erwartet aber logischerweise einen Buffer, der beschrieben werden kann.
Folgender Code funktioniert, basiert nicht auf irgendwelchen Pseudo-Funktionen
und erzeugt auch keine Memory-Leaks:
Delphi-Quellcode:
type
UNICODE_STRING =
packed record
Length: Word;
MaximumLength: Word;
Buffer: PWideChar;
end;
PUNICODE_STRING = ^UNICODE_STRING;
procedure RtlInitUnicodeString(DestinationString: PUNICODE_STRING; SourceString: LPWSTR);
stdcall;
external '
ntdll.dll';
procedure RtlRunEncodeUnicodeString(Hash: PUCHAR; Str: PUNICODE_STRING);
stdcall;
external '
ntdll.dll';
procedure RtlRunDecodeUnicodeString(Hash: UCHAR; Str: PUNICODE_STRING);
stdcall;
external '
ntdll.dll';
var
Source: PWideChar;
UnicodeString: UNICODE_STRING;
Hash: UCHAR;
S:
array of WideChar;
begin
Source := '
TestString';
// Init
SetLength(S, Length(Source) + 1);
ZeroMemory(@S[0], Length(S) * SizeOf(S[0]));
CopyMemory(@S[0], Source, Length(S) * SizeOf(S[0]));
RtlInitUnicodeString(@UnicodeString, @S[0]);
// Encode
// RtlRunEncodeUnicodeString automatically calculates a hash, if the initial value is zero
// http://doxygen.reactos.org/dc/d4b/lib_2rtl_2encode_8c_a2b44614e96788912d167d7cac4b7b501.html#a2b44614e96788912d167d7cac4b7b501
Hash := 0;
RtlRunEncodeUnicodeString(@Hash, @UnicodeString);
// Decode
RtlRunDecodeUniCodeString(Hash, @UnicodeString);
end;
Auch gehen würde folgendes (normale Stringkonstanten landen nicht in der read-only Section bzw. werden bei Zuweisung vermutlich umkopiert):
Delphi-Quellcode:
var
Source: WideString;
UnicodeString: UNICODE_STRING;
Hash: UCHAR;
begin
Source := 'TestString'#0;
RtlInitUnicodeString(@UnicodeString, @Source[1]);
Hash := 0;
RtlRunEncodeUnicodeString(@Hash, @UnicodeString);
Dann aber nicht vergessen vorher per Hand eine #0 an den Source String anzuhängen.