1

Lazarus(Free Pascal)の次のコードを使用して、メインウィンドウのハンドルを取得しようとしています。

function FindMainWindow(Pid: LongWord): LongWord;
type
  TParam = record
    Window: HWnd;
    Test: Integer;
    Pid: LongWord;
  end;
  PParam = ^TParam;
var
  Params: TParam;
  function _FindMainWindow(Wnd: HWnd; MyLParam: PParam): Bool; stdcall;
  var
    WinPid: DWord;
  begin
    with MyLParam^ do
    begin
      Test := 2;
      GetWindowThreadProcessID(Wnd, @WinPid);
      Result := (WinPid <> Pid) or (not IsWindowVisible(Wnd))
        or (not IsWindowEnabled(Wnd));
      if not Result then begin
        Window := Wnd;
      end;
    end;
  end;
begin
  Params.Pid := Pid;
  Params.Test := 1;
  EnumWindows(@_FindMainWindow, LParam(@Params));
  ShowMessage('Done!');
  ShowMessage(IntToStr(Params.Test));
  Result := Params.Window;
end; 

問題はParams.Test、コールバックを実行した後もまだ1であるということです。関数Params内のを変更したい。_FindMainWindow

注: 「アクセス違反」エラーが発生したためParams_FindMainWindow直接アクセスできませんでした。

4

1 に答える 1

3

確かにDelphiでは、FPCのようにも見えますが、ネストされた関数はコールバック関数として使用するには無効です。32ビットコンパイラを使用する場合、ネストされた関数をコールバックとして使用できることがあります。ただし、コールバック関数はWindowsユニットで型指定されていないポインターとして宣言されているため、このようなコードはコンパイラーによってのみ受け入れられます。Windowsユニットがそれらを手続き型として宣言した場合、コンパイラはネストされた関数の使用に反対していることがわかります。

64ビットDelphiコンパイラの場合、ネストされた関数をコールバックとして使用することはできません。コンパイラーでは先に進むことができますが、Windowsユニットでは型指定されていないポインターが使用されているため(上​​記を参照)、コールバック関数は正しく呼び出されません。どうやらそれはFPCにも当てはまります。コールバックにネストされた関数を使用するのをやめる必要があります。

ここで、FPCコンパイラとDelphiコンパイラの両方が同じ特性を持っているのは興味深いことです。私の推測では、スタックベースのx86ではなくレジスタベースの規約であるx64呼び出し規約が、stdcallこの問題の背後にある原動力であると思います。ネストされたx86register関数をコールバックとして使用しようとすると、実行時にも失敗することは間違いありません。

于 2012-06-22T11:36:27.737 に答える