在新挂钩的LoadResString方法中读取stringlist时获得StackOverflow异常



供参考-以下是我的代码,我在NewLoadResString函数中获得StackOverflow异常。这种情况就像我已经创建了两个字符串列表,即RecStrNameIdMap和NewStringValueList。RecStrNameIdMap是哈希字符串列表,用于存储名称和字符串标识符映射。这样我就可以引用资源字符串名称作为其标识符,即ID。

NewStringValueList是一个字符串列表,它包含了一些资源字符串的新值。

我已经在系统上连接了NewLoadResString方法。LoadResString方法。在新方法中,我正在检查我是否有NewStringValueList中给定的resourcestring的新值,然后获得该值并返回新的而不是旧的声明值。

发生堆栈溢出异常*

如果RecStrNameIdMap.IndexOfName(IntToStr(ResStringRec^.Identifier))>1然后

*有没有人可以检查一下为什么我得到这个错误。

unit UnitTest;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IniFiles, StdCtrls;
type
  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TMethodHook = class
  private
    aOriginal : packed array[ 0..4 ] of byte;
    pOldProc, pNewProc : pointer;
    pPosition : PByteArray;
  public
    constructor Create( pOldProc, pNewProc : pointer );
    destructor Destroy; override;
  end;

var
  Form2: TForm2;
implementation
{$R *.dfm}
ResourceString
  RS_1 = 'ABC';
  RS_2 = 'XYZ';
procedure TForm2.Button1Click(Sender: TObject);
var
  aMethodHook: TMethodHook;
  RecStrNameIdMap: THashedStringList;
  NewStringValueList: TStringList;
  {Hookup aNewProcedure on aOriginalProcedure}
  procedure RegisterProcedures(aOriginalProcedure, aNewProcedure: pointer);
  begin
    if Assigned(aOriginalProcedure) and Assigned(aNewProcedure) then
      aMethodHook := TMethodHook.Create( aOriginalProcedure, aNewProcedure);
  end;
  {Replacement for System.LoadResString}
  function NewLoadResString(ResStringRec: PResStringRec): String;
  var
    Buffer: array [0..4095] of char;
  begin
    if ResStringRec = nil then Exit;
    if ResStringRec.Identifier >= 64 * 1024 then
    begin
      Result := PChar(ResStringRec.Identifier);
    end
    else
    begin
      if RecStrNameIdMap.IndexOfName(IntToStr(ResStringRec^.Identifier)) > -1 then
      begin
        Result := NewStringValueList.Values[
          RecStrNameIdMap.Values[IntToStr(ResStringRec^.Identifier)]];
      end
      else
      begin
        SetString(Result, Buffer,
          LoadString(FindResourceHInstance(ResStringRec.Module^),
            ResStringRec.Identifier, Buffer, SizeOf(Buffer)));
      end;
    end;
  end;
  procedure CreateNameIdMapping;
  begin
    {This is done to get string name from ID}
    RecStrNameIdMap.CaseSensitive := False;
    RecStrNameIdMap.Add(Inttostr(PResStringRec(RS_2)^.Identifier)+'='+'XYZ');
  end;
begin
  aMethodHook := nil;
  try
    RecStrNameIdMap := THashedStringList.Create;
    NewStringValueList := TStringList.Create;
    CreateNameIdMapping;
    {Create new value list for ResourceStrings}
    NewStringValueList.Add('XYZ'+'='+'new value for ResourceString RS_2');
    RegisterProcedures(@System.LoadResString, @NewLoadResString);
    {This should return 'new value for ResourceString RS_2' instead of 'XYZ'}
    ShowMessage(RS_2);
    {This should return 'ABC' - no change in value}
    ShowMessage(RS_1);
  finally
    aMethodHook.Free;
    RecStrNameIdMap.Free;
    NewStringValueList.Free;
  end;
end;
{ TMethodHook }
constructor TMethodHook.Create(pOldProc, pNewProc: pointer);
var
  iOffset : integer;
  iMemProtect : cardinal;
  i : integer;
begin
  Self.pOldProc := pOldProc;
  Self.pNewProc := pNewProc;
  pPosition := pOldProc;
  iOffset := integer( pNewProc ) - integer( pointer( pPosition ) ) - 5;
  for i := 0 to 4 do aOriginal[ i ] := pPosition^[ i ];
  VirtualProtect( pointer( pPosition ), 5, PAGE_EXECUTE_READWRITE,
    @iMemProtect );
  pPosition^[ 0 ] := $E9;
  pPosition^[ 1 ] := byte( iOffset );
  pPosition^[ 2 ] := byte( iOffset shr 8 );
  pPosition^[ 3 ] := byte( iOffset shr 16 );
  pPosition^[ 4 ] := byte( iOffset shr 24 );
end;
destructor TMethodHook.Destroy;
var
  i : integer;
begin
  for i := 0 to 4 do pPosition^[ i ] := aOriginal[ i ];
  inherited;
end;
end.

看来替换过程不能是嵌套例程。
如文档中所述:

过程类型允许将过程和函数视为值,这些值可以赋值给变量或传递给其他过程和函数。

嵌套过程和函数(在其他例程中声明的例程)不能用作过程值,预定义的过程和函数也不能用作过程值。

过程类型是指针。虽然嵌套例程不能用作过程类型,但我认为指向嵌套例程的指针不能用作过程参数,否则该操作可能会像本例中那样产生不可预测的结果。
这个过程被正确地钩住了(你做到了);我提取了过程NewLoadResStringstackoverflow错误不再发生。
弹出的resourcestring始终是旧的,但我在NewLoadResString过程中没有做任何更改。
整个编辑单元如下。

unit UnitTest;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IniFiles, StdCtrls;
type
  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    RecStrNameIdMap: THashedStringList;
    NewStringValueList: TStringList;
  public
    { Public declarations }
  end;

type
  TMethodHook = class
  private
    aOriginal : packed array[ 0..4 ] of byte;
    pOldProc, pNewProc : pointer;
    pPosition : PByteArray;
  public
    constructor Create( pOldProc, pNewProc : pointer );
    destructor Destroy; override;
  end;

var
  Form2: TForm2;
implementation
{$R *.dfm}
ResourceString
  RS_1 = 'ABC';
  RS_2 = 'XYZ';

{Replacement for System.LoadResString}
function NewLoadResString(ResStringRec: PResStringRec): String;
var
  Buffer: array [0..4095] of char;
begin
  if ResStringRec = nil then Exit;
  if ResStringRec.Identifier >= 64 * 1024 then
  begin
    Result := PChar(ResStringRec.Identifier);
  end
  else
  begin
    if RecStrNameIdMap.IndexOfName(IntToStr(ResStringRec^.Identifier)) > -1 then
    begin
      Result := NewStringValueList.Values[
        RecStrNameIdMap.Values[IntToStr(ResStringRec^.Identifier)]];
    end
    else
    begin
      SetString(Result, Buffer,
        LoadString(FindResourceHInstance(ResStringRec.Module^),
          ResStringRec.Identifier, Buffer, SizeOf(Buffer)));
    end;
  end;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
  aMethodHook: TMethodHook;
  {Hookup aNewProcedure on aOriginalProcedure}
  procedure RegisterProcedures(aOriginalProcedure, aNewProcedure: pointer);
  begin
    if Assigned(aOriginalProcedure) and Assigned(aNewProcedure) then
      aMethodHook := TMethodHook.Create( aOriginalProcedure, aNewProcedure);
  end;
  procedure CreateNameIdMapping;
  begin
    {This is done to get string name from ID}
    RecStrNameIdMap.CaseSensitive := False;
    RecStrNameIdMap.Add(Inttostr(PResStringRec(RS_2)^.Identifier)+'='+'XYZ');
  end;
begin
  aMethodHook := nil;
  RecStrNameIdMap := THashedStringList.Create;
  NewStringValueList := TStringList.Create;
  try
    CreateNameIdMapping;
    {Create new value list for ResourceStrings}
    NewStringValueList.Add('XYZ'+'='+'new value for ResourceString RS_2');
    RegisterProcedures(@System.LoadResString, @NewLoadResString);
    {This should return 'new value for ResourceString RS_2' instead of 'XYZ'}
    ShowMessage(RS_2);
    {This should return 'ABC' - no change in value}
    ShowMessage(RS_1);
  finally
    aMethodHook.Free;
    RecStrNameIdMap.Free;
    NewStringValueList.Free;
  end;
end;
{ TMethodHook }
constructor TMethodHook.Create(pOldProc, pNewProc: pointer);
var
  iOffset : integer;
  iMemProtect : cardinal;
  i : integer;
begin
  Self.pOldProc := pOldProc;
  Self.pNewProc := pNewProc;
  pPosition := pOldProc;
  iOffset := integer( pNewProc ) - integer( pointer( pPosition ) ) - 5;
  for i := 0 to 4 do aOriginal[ i ] := pPosition^[ i ];
  VirtualProtect( pointer( pPosition ), 5, PAGE_EXECUTE_READWRITE,
    @iMemProtect );
  pPosition^[ 0 ] := $E9;
  pPosition^[ 1 ] := byte( iOffset );
  pPosition^[ 2 ] := byte( iOffset shr 8 );
  pPosition^[ 3 ] := byte( iOffset shr 16 );
  pPosition^[ 4 ] := byte( iOffset shr 24 );
end;
destructor TMethodHook.Destroy;
var
  i : integer;
begin
  for i := 0 to 4 do pPosition^[ i ] := aOriginal[ i ];
  inherited;
end;
end.

相关内容

  • 没有找到相关文章

最新更新