enumなんとかをfor..inで、その2
できた…眠いので解説しません。ソース貼って終わり。
type
TWindowEnumerator = class(TObject)
caller_ebx, caller_esi, caller_edi, caller_ebp, caller_eip: Pointer;
enum_ebx, enum_esi, enum_edi, enum_esp, enum_eip: Pointer;
save_esp, save_eip: Pointer;
base_esp: Pointer;
FState: (Enumerating, Terminated, Ended);
FNext, FCurrent: HWND;
procedure BeforeDestruction; override;
function MoveNext: Boolean;
function GetCurrent: HWND;
property Current: HWND read GetCurrent;
end;
function Each(Wnd: HWND; Self: TWindowEnumerator): Boolean cdecl;
asm
mov edx, Wnd
mov eax, Self
push ebp
mov TWindowEnumerator[eax].FNext, edx
mov TWindowEnumerator[eax].enum_ebx, ebx
mov TWindowEnumerator[eax].enum_esi, esi
mov TWindowEnumerator[eax].enum_edi, edi
mov TWindowEnumerator[eax].enum_esp, esp
mov TWindowEnumerator[eax].enum_eip, offset @Next
mov ebx, TWindowEnumerator[eax].caller_ebx
mov esi, TWindowEnumerator[eax].caller_esi
mov edi, TWindowEnumerator[eax].caller_edi
mov edx, TWindowEnumerator[eax].caller_eip
mov ebp, TWindowEnumerator[eax].caller_ebp
jmp edx
@Next:
pop ebp
mov eax, Self
mov al, TWindowEnumerator[eax].FState
end;
function TWindowEnumerator.MoveNext: Boolean;
asm
{FCurrent := FNext}
mov edx, TWindowEnumerator[eax].FNext
mov TWindowEnumerator[eax].FCurrent, edx
{終了判定}
mov dl, TWindowEnumerator[eax].FState
test dl, dl
jnz @Terminated
{コンテキスト保存}
pop ecx
mov TWindowEnumerator[eax].save_esp, esp
mov TWindowEnumerator[eax].save_eip, ecx
{スイッチ}
mov TWindowEnumerator[eax].caller_ebx, ebx
mov TWindowEnumerator[eax].caller_esi, esi
mov TWindowEnumerator[eax].caller_edi, edi
mov TWindowEnumerator[eax].caller_ebp, ebp
mov TWindowEnumerator[eax].caller_eip, offset @Next
mov ebx, TWindowEnumerator[eax].enum_ebx
mov esi, TWindowEnumerator[eax].enum_esi
mov edi, TWindowEnumerator[eax].enum_edi
mov esp, TWindowEnumerator[eax].enum_esp
mov edx, TWindowEnumerator[eax].enum_eip
jmp edx
@Next:
{コンテキスト復帰}
mov esp, TWindowEnumerator[eax].save_esp
mov ecx, TWindowEnumerator[eax].save_eip
push ecx
mov al, 1
ret
@Terminated:
cmp dl, Terminated
jne @End
mov TWindowEnumerator[eax].FState, Ended
mov al, 1
ret
@End:
mov al, 0
end;
function TWindowEnumerator.GetCurrent: HWND;
begin
Result := FCurrent
end;
procedure TWindowEnumerator.BeforeDestruction;
asm
mov dl, TWindowEnumerator[eax].FState
test dl, dl
jnz @Exit
{終了フラグ}
mov TWindowEnumerator[eax].FState, Terminated
{コンテキスト保存}
pop ecx
mov TWindowEnumerator[eax].save_eip, ecx
mov TWindowEnumerator[eax].save_esp, esp
{スイッチ}
mov TWindowEnumerator[eax].caller_ebx, ebx
mov TWindowEnumerator[eax].caller_esi, esi
mov TWindowEnumerator[eax].caller_edi, edi
mov TWindowEnumerator[eax].caller_ebp, ebp
mov TWindowEnumerator[eax].caller_eip, offset @Next
mov ebx, TWindowEnumerator[eax].enum_ebx
mov esi, TWindowEnumerator[eax].enum_esi
mov edi, TWindowEnumerator[eax].enum_edi
mov esp, TWindowEnumerator[eax].enum_esp
mov edx, TWindowEnumerator[eax].enum_eip
jmp edx
@Next:
{コンテキスト復帰}
mov esp, TWindowEnumerator[eax].save_esp
mov ecx, TWindowEnumerator[eax].save_eip
push ecx
{スタック巻き戻し}
mov eax, TWindowEnumerator[eax].base_esp
lea edx, [eax - 24] {BeforeDestruction, @BeforeDestruction(pop*2), Destroy, Finally}
mov eax, esp
mov ecx, 24
push edx
call System.Move
pop esp
@Exit:
end;
type
TEnumWindows = record
function GetEnumerator: TWindowEnumerator;
end;
function TEnumWindows.GetEnumerator: TWindowEnumerator;
const
VMT: TClass = TWindowEnumerator;
asm
{コンストラクタ呼び出し}
mov dl, 1
mov eax, [VMT]
call TWindowEnumerator.Create
{フィールド代入}
lea edx, [esp + 4]
mov TWindowEnumerator[eax].base_esp, edx
mov TWindowEnumerator[eax].caller_ebx, ebx
mov TWindowEnumerator[eax].caller_esi, esi
mov TWindowEnumerator[eax].caller_edi, edi
mov TWindowEnumerator[eax].caller_ebp, ebp
mov edx, [esp]
mov TWindowEnumerator[eax].caller_eip, edx
{Self保存}
push ebx
mov ebx, eax
{呼び出し}
mov edx, eax
mov eax, offset Each
call EnumerateWindows
{Self復帰}
mov eax, ebx
pop ebx
{デストラクタから来たならデストラクタへ戻る}
mov dl, TWindowEnumerator[eax].FState
test dl, dl
jz @Exit
mov edx, TWindowEnumerator[eax].caller_eip
mov ebp, TWindowEnumerator[eax].caller_ebp
jmp edx
@Exit:
{終了フラグ}
mov TWindowEnumerator[eax].FState, Terminated
end;