1

Win32Delphiプログラムで.NETランタイムをホストできるようにする独自のglue-layer-code-thingamajigがあります。これにより、時間の経過とともに.NETへの段階的な移行が可能になりました。

しかし、時々問題が発生します。昨日、SOでJclの.NETホストの実装に関する回答を見たので、明らかな違いがあるかどうかを確認したいと思いました。

あることがわかりましたが、それが何をするのか、なぜ、そして私が同じことをする必要があるのか​​どうかはわかりません。確かに試してみますが、この奇妙なコードの背後にある理由を理解している他の誰かに、それが何をするのかを教えてもらいたいと思います。

やがて、Jcl実装の使用に切り替える可能性がありますが、リリースが差し迫っているため、現在の問題を修正するために絶対に必要でない限り、このレベルのコードでの大規模なオーバーホールは正当化されません。切り替えることをお勧めします。

とにかく、違いは、.NET関数を呼び出して.NETランタイムをロードしてバインドする方法、基本的には.NETdllからエクスポートされた関数を呼び出す方法にあります。

これが私のコードです:

type
  TCorBindToRuntimeEx = function(pwszVersion: PWideChar;
    pwszBuildFlavor: PWideChar;
    startupFlags: DWord; rclsid, riid: PGUID;
    out ppv: IUnknown): Integer; stdcall;
...
var
  CorBindToRuntimeEx  : TCorBindtoRuntimeEx = nil;
...
CorBindToRuntimeEx := GetProcAddress(Runtimehandle, 'CorBindToRuntimeEx');
...
clsid := CLASS_CorRuntimeHost;
iid := IID_ICorRuntimeHost;
rc := CorBindToRuntimeEx('v2.0.50727', 'wks', 0, @clsid,
    @iid, UnkRuntimeEngine);

ここで、GetProcAddressを使用して、エクスポートされた関数のアドレスを変数にロードし、stdcall関数ポインターとして入力してから呼び出します。これはうまくいきます。私が言ったように、いくつかのケースで奇妙なエラーメッセージに関するいくつかの問題。

さて、ここに彼らのコードがあります、そしてアセンブラーコードを持つ関数に特に注意を払ってください。

function CorBindToRuntimeEx(pwszVersion, pwszBuildFlavor: PWideChar;
  startupFlags: DWORD; const rclsid: TCLSID; const riid: TIID;
  out pv): HRESULT; stdcall;
{$EXTERNALSYM CorBindToRuntimeEx}
...
var
  _CorBindToRuntimeEx: Pointer = nil;

function CorBindToRuntimeEx;
begin
  GetProcedureAddress(_CorBindToRuntimeEx, mscoree_dll,
    'CorBindToRuntimeEx');
  asm
    mov esp, ebp
    pop ebp
    jmp [_CorBindToRuntimeEx]
  end;
end;
...
OleCheck(CorBindToRuntimeEx(PWideCharOrNil(ClrVer),
  PWideChar(ClrHostFlavorNames[Flavor]), Flags,
  CLASS_CorRuntimeHost, IID_ICorRuntimeHost,
  FDefaultInterface));

ここでSOで水平スクロールバーを回避するためにコードを少し再フォーマットしましたが、いくつかの改行とインデントを追加するだけで、コードはそのままです。

最後の呼び出しはおそらく無関係であり、基本的には同じパラメーターを渡します(オプション値として0を渡すことに注意してください。ただし、Jclコードが使用するのと同じ特定の引数を使用して試しましたが、問題はまだ残っています。現在)。

だから、私の質問は、アセンブラコードは彼**が何をするのかということです。私はそれが技術的な意味で何をするかを知っています、私は以前にアセンブリをプログラミングしていたので、それはスタックポインタを操作します。

問題は、なぜこれを行わなければならないのかということです。わからない。

結局、スタックフレームが完全ではないという stdcallことでしょうか?

今日は教えてください。


編集:わかりました、それに応じてコードを変更しましたが、まだ問題が残っているので、そうではありませんでした。結局のところ、サードパーティのコードを掘り下げるWinDbgを実行しているようです。

4

1 に答える 1

5

アセンブラ コードは、CorBindToRuntimeEx のスタック フレームを削除します。CorBindToRuntimeEx を呼び出すと、すべてのパラメーターがスタックにプッシュされます (=> stdcall)。次に、この関数は GetProcedureAddress を呼び出して、'CorBindToRuntimeEx' 関数を指すようになったグローバル _CorBindToRuntimeEx 変数を初期化します。

GetProcedureAddress が返された後、_CorBindToRuntimeEx 関数を呼び出す必要があります。しかし、ここで問題があります。Delphi は自動的に「push ebp; mov ebp,esp」をコードに追加しました(「begin」がある場所)。そして、そのスタックフレームを削除するために、「mov esp,ebp; pop ebp」が使用されます。次に、「jmp [_CorBindToRuntimeEx]」は、実行ポインターを _CorBindToRuntimeEx 関数に設定します。この関数は、CorBindToRuntimeEx 関数からの戻りアドレスを使用します。

于 2009-04-22T10:27:55.667 に答える