;##########################################################################
.386
.model flat, stdcall
option casemap:none
title Auto-Complete Combo Box
;##########################################################################
include C:\masm32\include\windows.inc
include C:\masm32\include\kernel32.inc
include C:\masm32\include\user32.inc
includelib C:\masm32\lib\kernel32.lib
includelib C:\masm32\lib\user32.lib
;##########################################################################
m2m MACRO M1, M2
	push	M2
	pop	M1
ENDM
m2mx MACRO M1, M2
	mov	eax, M2
	mov	M1, eax
ENDM
return MACRO RETVALUE
	mov	eax, RETVALUE
	ret
ENDM
iif MACRO condition, if_true, if_false, return
	.if condition
		mov	return, if_true
	.else
		mov	return, if_false
	.endif
ENDM
iifs MACRO condition, if_true, if_false, return
	mov	return, if_false
	.if condition
		mov	return, if_true
	.endif
ENDM
;##########################################################################
;##########################################################################
	CurDate		TEXTEQU		<">, @Date, <">
	CurTime		TEXTEQU		<">, @Time, <">
	CurFileName	TEXTEQU		<">, @FileCur, <">
;##########################################################################
WndProc		PROTO	:DWORD,:DWORD,:DWORD,:DWORD
ErrorHandler	PROTO C	:DWORD,:DWORD,:DWORD,:DWORD
ExceptionFilter	PROTO	:DWORD
;##########################################################################
.const
	szAppTitle	db		"Auto-Complete Combo Box", 0
	szMsgAbout	db		"Auto-Complete Combo Box", 13, 10
			db		"Built on ", CurDate, " ", CurTime, 13, 10
			db		"Version 1.0", 13, 10
			db		"Coded by comrade <comrade2k@hotmail.com>", 13, 10
			db		"Web: http://www.comrade64.com/", 13, 10
			db		"http://euro.comrade64.com/", 13, 10
			db		"http://comrade.ownz.com/", 13, 10
			db		"http://comrade.win32asm.com/", 13, 10
			db		"http://comrade64.cjb.net/", 13, 10
			db		"http://comrade.hpacv.dk/", 13, 10
			db		"IRC: #asm, #coders, #win32asm on EFnet", 0
	szMenuAbout	db		"&About Auto-Complete Combo Box...", 0
	szError		db		"Error", 0
	szErrorThread	db		"Error at %08Xh", 13, 10, "Registers:", 13, 10, "eax = %08Xh ebx = %08Xh ecx = %08Xh", 13, 10, "edx = %08Xh esp = %08Xh ebp = %08Xh", 13, 10, "esi = %08Xh edi = %08Xh", 13, 10, 13, 10, "Recovering...", 0
	szErrorFinal	db		"Error at %08Xh", 13, 10, "Quitting...", 0
	szFileMask	db		"*.*", 0
;##########################################################################
.data
;##########################################################################
.data?
	hIcon		dd		?
	hFind		dd		?
	szMessage	db		256 dup (?)
	seh		dd		6 dup (?)

	data_start	equ		$
	mbp		MSGBOXPARAMS	<>
	fd		WIN32_FIND_DATA	<>
	szText		db		256 dup (?)
	szItem		db		256 dup (?)
	dwTextLength	dd		?
	dwItemLength	dd		?
	bCaseSensitive	db		?
	data_size	equ		$ - data_start
;##########################################################################
.code
start:	invoke	SetUnhandledExceptionFilter, ADDR ExceptionFilter
	push	edi
	xor	eax, eax
	mov	ecx, data_size shr 2
	mov	edi, data_start
	rep	stosd
	IF data_size AND 3
		mov	edi, data_start
		mov	ecx, data_size and 3
		rep	stosb
	ENDIF
	pop	edi
	invoke	GetModuleHandle, eax
	mov	[mbp.hInstance], eax
	invoke	DialogBoxParam, eax, 100, 0, ADDR WndProc, eax
	invoke	ExitProcess, eax
;#########################################################################
WndProc proc hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
	.if [uMsg]==WM_INITDIALOG
		mov	eax, [hWnd]
		mov	[mbp.hwndOwner], eax
		invoke	GetSystemMenu, eax, 0
		push	OFFSET szMenuAbout
		push	10
		push	MFT_STRING
		push	eax
		invoke	AppendMenu, eax, MFT_SEPARATOR, 0, 0
		call	AppendMenu
		invoke	LoadIcon, [lParam], 2
		mov	[hIcon], eax
		invoke	SendMessage, [hWnd], WM_SETICON, 1, eax

		; enumerate files in the current directory and add them to the combobox
		invoke	FindFirstFile, ADDR szFileMask, ADDR fd
		cmp	eax, INVALID_HANDLE_VALUE
		mov	[hFind], eax
		je	@@quit
	@@file:	test	[fd.dwFileAttributes], FILE_ATTRIBUTE_DIRECTORY
		.if zero?	; its not a directory
			invoke	SendDlgItemMessage, [hWnd], 101, CB_ADDSTRING, 0, ADDR fd.cFileName
		.endif
		invoke	FindNextFile, [hFind], ADDR fd
		test	eax, eax
		jnz	@@file
		invoke	FindClose, [hFind]
	.elseif [uMsg]==WM_SYSCOMMAND
		cmp	[wParam], 10
		je	@@msga
	.elseif [uMsg]==WM_COMMAND
		mov	eax, [wParam]
		.if eax==CBN_EDITUPDATE shl 16 + 101
			assume	fs:nothing
			push	OFFSET ErrorHandler
			push	FS:[0]
			mov	[seh], esp
			mov	[seh+4], ebp
			mov	[seh+8], ebx
			mov	[seh+12], esi
			mov	[seh+16], edi
			mov	[seh+20], OFFSET @@safe
			mov	FS:[0], esp
			; critical code
			; get current combobox text
			invoke	GetWindowText, [lParam], ADDR szText, sizeof szText
			cmp	eax, [dwTextLength]	; erased?
			mov	[dwTextLength], eax
			jle	@@safe
			test	eax, eax	; zero length?
			je	@@safe
			invoke	IsDlgButtonChecked, [hWnd], 102
			mov	[bCaseSensitive], al
			; loop through all the items in the combobox
			invoke	SendMessage, [lParam], CB_GETCOUNT, 0, 0
			cmp	eax, CB_ERR
			je	@@safe
			push	edi
			push	esi
			push	ebx
			push	eax
			xor	ebx, ebx
		@@item:	invoke	SendMessage, [lParam], CB_GETLBTEXT, ebx, ADDR szItem
			mov	[dwItemLength], eax
			inc	ebx
			mov	esi, OFFSET szText
			mov	edi, OFFSET szItem
			mov	ecx, [dwTextLength]
		@@cmps:	lodsb
			mov	ah, [edi]
			cmp	[bCaseSensitive], 0
			jne	@@cmp1
			cmp	al, "Z"
			ja	@@cmp0
			cmp	al, "A"
			jb	@@cmp0
			add	al, 32
		@@cmp0:	cmp	ah, "Z"
			ja	@@cmp1
			cmp	ah, "A"
			jb	@@cmp1
			add	ah, 32
		@@cmp1:	cmp	al, ah
			jne	@@chki
			inc	edi
			loopd	@@cmps
			invoke	SetWindowText, [lParam], ADDR szItem
			mov	eax, [dwTextLength]
			shl	eax, 16
			or	eax, [dwItemLength]
			invoke	SendMessage, [lParam], CB_SETEDITSEL, 0, eax
			mov	ebx, [esp]
		@@chki:	cmp	ebx, [esp]	; see if we're done looping
			jne	@@item
			pop	eax
			pop	ebx
			pop	esi
			pop	edi
		@@safe:	pop	FS:[0]
			add	esp, 4
		.elseif ax==103		; About
		@@msga:	mov	[mbp.cbSize], sizeof mbp
			mov	[mbp.lpszText], OFFSET szMsgAbout
			mov	[mbp.lpszCaption], OFFSET szAppTitle
			mov	[mbp.dwStyle], MB_OK OR MB_APPLMODAL OR MB_USERICON
			mov	[mbp.lpszIcon], 2
			invoke	MessageBoxIndirect, ADDR mbp
		.elseif ax==104		; Close
			invoke	PostMessage, [hWnd], WM_CLOSE, 0, 0
		.endif
	.elseif [uMsg]==WM_CLOSE
		invoke	EndDialog, [hWnd], 0
		invoke	DestroyIcon, [hIcon]
	.endif
@@quit:	xor	eax, eax
	ret
WndProc endp
;##########################################################################
ErrorHandler proc C lpExcept:DWORD, lpFrame:DWORD, lpContext:DWORD, lpDispatch:DWORD
	mov	eax, [lpExcept]
	mov	ecx, [lpContext]
	invoke	wsprintf, ADDR szMessage, ADDR szErrorThread, [eax][EXCEPTION_RECORD.ExceptionAddress], [ecx][CONTEXT.regEax], [ecx][CONTEXT.regEbx], [ecx][CONTEXT.regEcx], [ecx][CONTEXT.regEdx], [ecx][CONTEXT.regEsp], [ecx][CONTEXT.regEbp], [ecx][CONTEXT.regEsi], [ecx][CONTEXT.regEdi]
	invoke	MessageBox, [mbp.hwndOwner], ADDR szMessage, ADDR szError, MB_OK OR MB_ICONHAND OR MB_APPLMODAL

	mov	eax, [lpContext]
	m2m	[eax][CONTEXT.regEsp], [seh]
	m2m	[eax][CONTEXT.regEbp], [seh+4]
	m2m	[eax][CONTEXT.regEbx], [seh+8]
	m2m	[eax][CONTEXT.regEsi], [seh+12]
	m2m	[eax][CONTEXT.regEdi], [seh+16]
	m2m	[eax][CONTEXT.regEip], [seh+20]

	xor	eax, eax	; continue execution
	ret
ErrorHandler endp
;##########################################################################
ExceptionFilter proc lpExcept:DWORD
	mov	eax, [lpExcept]
	invoke	wsprintf, ADDR szMessage, ADDR szErrorFinal, [eax][EXCEPTION_RECORD.ExceptionAddress]
	invoke	MessageBox, [mbp.hwndOwner], ADDR szMessage, ADDR szError, MB_OK OR MB_ICONHAND OR MB_APPLMODAL
	invoke	EndDialog, [mbp.hwndOwner], eax
	invoke	DestroyIcon, [hIcon]
	invoke	ExitProcess, 0
	xor	eax, eax
	inc	eax		; EXCEPTION_EXECUTE_HANDLER
	ret
ExceptionFilter endp
;##########################################################################
;##########################################################################
;##########################################################################
end start