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;