4

Delphiで記述されたレガシーアプリケーションがあり、次のメカニズムを構築する必要があります。

  1. 読書と
  2. 書き込み

TStringGridとの間のデータ。

アプリケーションのソースコードがありません。自動化インターフェースがなく、ベンダーが提供する可能性はほとんどありません。

したがって、私は作成しました

  1. 注入するC++DLL
  2. Delphi DLL(私が書いた)に
  3. レガシーアプリケーションのアドレス空間。

DLL 2は、レガシーアプリケーション内のTStringGridインスタンスにアクセスし、セル値を読み取り、それらをデバッグログに書き込みます。

読書はうまくいきます。しかし、次のような呼び出しを使用してグリッドセルにデータを書き込もうとすると

realGrid.Cells[1,1] := 'Test';

アクセス違反が発生します。

コードは次のとおりです。

procedure DllMain(reason: integer) ;
type
  PForm = ^TForm;
  PClass = ^TClass;
  PStringGrid = ^TStringGrid;
var
[...]
begin
  if reason = DLL_PROCESS_ATTACH then
  begin
    handle := FindWindow('TForm1', 'FORMSSSSS');

    formPtr := PForm(GetVCLObjectAddr(handle) + 4);

    if (not Assigned(formPtr)) then
    begin
      OutputDebugString(PChar('Not assigned'));
      Exit;
    end;

    form := formPtr^;

    // Find the grid component and assign it to variable realGrid
    [...]

    // Iterate over all cells of the grid and write their values into the debug log
    for I := 0 to realGrid.RowCount - 1 do
      begin
        for J := 0 to realGrid.ColCount - 1 do
          begin
            OutputDebugString(PChar('Grid[' + IntToStr(I) + '][' + IntToStr(J) + ']=' + realGrid.Cells[J,I]));
            // This works fine
          end;
      end;

    // Now we'll try to write data into the grid
    realGrid.Cells[1,1] := 'Test'; // Crash - access violation
  end;
end; (*DllMain*)

アクセス違反の問題が発生することなく、TStringGridにデータを書き込むにはどうすればよいですか?

4

2 に答える 2

1

このアプローチは単に機能しません。ターゲット実行可能ファイルに2つのVCLインスタンスがあります。1つはターゲットアプリが所有し、もう1つはDLLが所有します。これは、1つのVCLインスタンスが多すぎます。ターゲットアプリとDLLの両方をビルドするためにまったく同じバージョンのDelphiを使用すれば、それを回避できる可能性があります。

ただし、2つのヒープマネージャーが引き続き使用できます。また、コードは、異なるVCLインスタンス間でヒープに割り当てられたメモリを渡します。一方のヒープで割り当てを行い、もう一方のヒープで割り当てを解除します。これは機能せず、アクセス違反が発生します。

DLLのヒープに割り当てられた文字列を、ターゲットアプリのヒープを使用する文字列グリッドオブジェクトに渡します。それはうまくいきません。

Cells[i,j]アクセス違反は、DLLコードがターゲットアプリのヒープマネージャーによって割り当てられた以前の値の割り当てを解除しようとした時点で発生すると思います。

基本的に、あなたが試みていることはうまくいきません。ターゲットアプリの実装のアドレスを見つけて、TStringGrid.SetCellそれを偽造することができます。ただし、ターゲットアプリの実装などを見つけて、DLLからターゲットアプリに渡ったすべてのダイナミックメモリがターゲットアプリのヒープによって割り当てられ、割り当てが解除されていることを確認する必要もありGetMemますFreeMem。あなたはこの仕事をする仕事の悪魔を持っているでしょう。もちろん、ターゲットアプリとDLLの両方が共有メモリマネージャーを使用している場合は、このアプローチをうまく実行できる可能性があります。

はるかに簡単なのは、キーボード入力を偽造することです。私は個人的に、AutoHotKeyを使用してその実現可能性を調査します。

于 2012-09-17T09:54:58.813 に答える
1

ヒープの使用に関連するすべてのものは、そこで非常に大きなリスクにさらされています。Jedi CodeLibを試して、オブジェクトツリーをマージし、EXEとDLLで同じ単一のヒープを確保することができますが、それは非常に脆弱なソリューションになります。

VMT呼び出しが多かれ少なかれ安全であり、コンパイラが文字列を解放するのをパラノイア的に阻止しようとしていることを期待して、スケッチは次のようになります。

type TSGCracker = class(Grids.TStringGrid); // access to protected functions.
....
var s: string;
function dummy(s: string);  // not-inline! pretend we need and use the value!
   begin Result := s + '2'; end; 
begin
   ...
   s := 'Test';   
   TSGCracker(realGrid).SetEditText(1,1, s);
   dummy( s+'1');
   ...
end;

ただし、ホストEXEで使用されている場合は、TStringGrid.OnSetEditTextが呼び出される可能性があります。

于 2012-09-17T11:22:21.953 に答える