なので。関連する質問を閉じてから-以下にさらに例を追加しました。
以下の単純なコード(トップレベルのIeウィンドウを検索し、その子を列挙する)は、「32ビットWindows」ターゲットプラットフォームで正常に機能します。以前のバージョンのDelphiでも問題はありません。
procedure TForm1.Button1Click(Sender: TObject);
function EnumChildren(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;
const
Server = 'Internet Explorer_Server';
var
ClassName: array[0..24] of Char;
begin
Assert(IsWindow(hwnd)); // <- Assertion fails with 64-bit
GetClassName(hwnd, ClassName, Length(ClassName));
Result := ClassName <> Server;
if not Result then
PUINT_PTR(lParam)^ := hwnd;
end;
var
Wnd, WndChild: HWND;
begin
Wnd := FindWindow('IEFrame', nil); // top level IE
if Wnd <> 0 then begin
WndChild := 0;
EnumChildWindows(Wnd, @EnumChildren, UINT_PTR(@WndChild));
if WndChild <> 0 then
..
end;
Assert
「64ビットWindows」ターゲットプラットフォームで失敗する場所を示すためにを挿入しました。コールバックのネストを解除しても、コードに問題はありません。
パラメータで渡された誤った値が単なるゴミなのか、メモリアドレスの配置ミスによるものなのかわかりません(呼び出し規約?)。ネストされたコールバックは、そもそも絶対にやるべきではないことを実際に行っているのでしょうか。それとも、これは私が生きなければならない単なる欠陥ですか?
編集:
Davidの答えに応えて、同じコードがEnumChildWindows
型付きコールバックで宣言しました。32ビットで正常に
動作します:(
編集:「@」演算子をまだ使用しているため、以下はDavidの言うことを実際にはテストしません。演算子では正常に動作しますが、削除すると、 -コールバックをネストします)
type
TFNEnumChild = function(hwnd: HWND; lParam: LPARAM): Bool; stdcall;
function TypedEnumChildWindows(hWndParent: HWND; lpEnumFunc: TFNEnumChild;
lParam: LPARAM): BOOL; stdcall; external user32 name 'EnumChildWindows';
procedure TForm1.Button1Click(Sender: TObject);
function EnumChildren(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;
const
Server = 'Internet Explorer_Server';
var
ClassName: array[0..24] of Char;
begin
Assert(IsWindow(hwnd)); // <- Assertion fails with 64-bit
GetClassName(hwnd, ClassName, Length(ClassName));
Result := ClassName <> Server;
if not Result then
PUINT_PTR(lParam)^ := hwnd;
end;
var
Wnd, WndChild: HWND;
begin
Wnd := FindWindow('IEFrame', nil); // top level IE
if Wnd <> 0 then begin
WndChild := 0;
TypedEnumChildWindows(Wnd, @EnumChildren, UINT_PTR(@WndChild));
if WndChild <> 0 then
..
end;
実際、この制限はWindows APIコールバックに固有のものではありませんが、その関数のアドレスをの変数に取り込んでprocedural type
、たとえばカスタムコンパレータとしてに渡す場合にも同じ問題が発生しTList.Sort
ます。
http://docwiki.embarcadero.com/RADStudio/Rio/en/Procedural_Types
procedure TForm2.btn1Click(Sender: TObject);
var s : TStringList;
function compare(s : TStringList; i1, i2 : integer) : integer;
begin
result := CompareText(s[i1], s[i2]);
end;
begin
s := TStringList.Create;
try
s.add('s1');
s.add('s2');
s.add('s3');
s.CustomSort(@compare);
finally
s.free;
end;
end;
Access Violation
32ビットとしてコンパイルすると期待どおりに動作しますが、Win64用にコンパイルすると失敗します。関数内の64ビットバージョンの場合compare
、s = nil
およびi2
=ランダムな値。
compare
また、関数の外で関数を抽出すると、Win64ターゲットでも期待どおりに機能しbtn1Click
ます。