OpenBtn		equ 128
EditBtn		equ 129
BuildBtn	equ 130
ExecuteBtn	equ 131
ShowBtn		equ 132
Edit1		equ 133
Edit2		equ 134
OkBtn		equ 135
OptEdt		equ 136
OptionBtn	equ 137

.486
.model flat,stdcall
option casemap:none

include windows.inc

irp lb,<kernel32,user32,comdlg32,shell32,gdi32>
include &lb&.inc
includelib &lb&.lib
endm

DlgProc	PROTO :DWORD,:DWORD,:DWORD,:DWORD
FormExecCmd PROTO :DWORD
Exec PROTO :DWORD
threadproc PROTO

.data
ml	db "ml.exe /c /coff /Cp /ID:\Villain\Masm\Include\ !.asm",0Dh,0Ah
rc	db "rc.exe /iD:\Villain\Masm\Bin\ !.rc",0Dh,0Ah
link	db "link.exe /subsystem:windows /LIBPATH:D:\Villain\Masm\Lib !.obj !.res",0Dh,0Ah
	db "cmd /C del !.obj",0Dh,0Ah
	db "cmd /C del !.res",0
	
DlgName		db "MainWindow",0
OptName		db "OptionWindow",0
MainIcon	db "MainIcon",0

inf		db "information",0
compile		db "Project was not compiled!",0

openfilehdr	db "Open assember file",0
msk		db "asember files (*.asm)",0
		db "*.asm",0,0

OPT		equ "tpo."
RC		equ "cr."
ASM		equ "msa."
EXE		equ "exe."

hInstance	dd 0
ProjectName	dd 0
ProjectNameSz	dd 0

blink		dd 0
mainhwnd	dd 0
hthread		dd 0
OptWndHnd	dd 0
OptThread	dd 0

;MMF
fSize		equ 1024
hFile		dd 0
fMap		dd 0
pData		dd 0

;выполнение с перенаправлением вывода и ошибок
hRead		dd 0
hWrite		dd 0
sat		SECURITY_ATTRIBUTES 	<0>
startupinfo 	STARTUPINFO 		<0>
pinfo		PROCESS_INFORMATION 	<0>

.data?
tmp		dd 1024 dup (?)
filename	db 512 dup(?)
junk		dd ?

.code
_Start:
	invoke	GetModuleHandle, NULL
	mov	hInstance,eax

	invoke	DialogBoxParam, hInstance, ADDR DlgName,0,addr DlgProc,0

OptThreadProc:
	invoke	DialogBoxParam, hInstance, ADDR OptName,mainhwnd,addr DlgProc,1 ;lParam=1 of WM_INITDIALOG
	invoke	ExitProcess,eax
	
;*****************window proc********************
DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
pushad
.IF 	uMsg==WM_CLOSE
	Call	CloseMMF
		
	invoke	SetCaretBlinkTime,blink
	invoke	TerminateThread,hthread,0
	invoke	PostQuitMessage,0

.ELSEIF	uMsg==WM_SYSCOMMAND
	.IF ((wParam==SC_MAXIMIZE)||(wParam==0F032h))	;CaptionDblClick=0F032h
		Push	SWP_SHOWWINDOW			;6 parameter
	
		mov	ebx,offset tmp
		assume	ebx:ptr RECT
			invoke	GetWindowRect,hWnd,ebx
			mov	eax,[ebx].bottom
			sub	eax,[ebx].top
			Push	eax			;5 parameter

			mov	esi,[ebx].right
			sub	esi,[ebx].left
			Push	esi			;4 parameter
		assume	ebx:nothing
			
		Push	0				;3 parameter
		
		invoke	GetSystemMetrics,SM_CXSCREEN
		sub	eax,esi
		Push	eax				;2 parameter
		
		Push	0				;1 parameter
		Push	hWnd				;0 parameter
	 	Call	SetWindowPos
	.ELSE	;call	inherited
		popad
		mov eax,FALSE
		ret
	.ENDIF

.ELSEIF	uMsg==WM_INITDIALOG
;save windowhandle
	.IF lParam==0; MainWindow
		mov	eax,hWnd
		mov	mainhwnd,eax
	;check showbtn
		invoke	SendDlgItemMessage,hWnd,ShowBtn,BM_SETCHECK,BST_CHECKED,0
	;load icon
		invoke	LoadIcon,hInstance,offset MainIcon
		invoke	SendMessage,hWnd,WM_SETICON,ICON_BIG,eax

	;speed of cursor blinking
		invoke	GetCaretBlinkTime
		mov	blink,eax
		invoke	SetCaretBlinkTime,030h
	.ELSE ;lParam==1 Option Window
		invoke	SetDlgItemText,hWnd,OptEdt,pData
	.ENDIF
	;Update window
	invoke	UpdateWindow,hWnd

.ELSEIF	uMsg==WM_CTLCOLOREDIT
	invoke SetTextColor,wParam,Green
	invoke SetBkColor,wParam,Black
	invoke GetStockObject,BLACK_BRUSH
	ret
			
.ELSEIF	uMsg==WM_COMMAND
	mov	eax,wParam
	.IF ax==Edit2
		
	.ELSEIF ax==OpenBtn
		;clear widow
		invoke	SetDlgItemText,hWnd,Edit2,0

		invoke	RtlZeroMemory,offset tmp,1024
		mov	ebx,offset tmp
		
		assume	ebx:ptr OPENFILENAMEA
		mov	[ebx].lStructSize,size OPENFILENAMEA
		mov	eax,hWnd
		mov	[ebx].hWndOwner,eax
		mov	[ebx].lpstrTitle,offset openfilehdr
		mov	[ebx].lpstrFilter,offset msk
		mov	[ebx].lpstrFile,offset filename
		mov	[ebx].nMaxFile,255
		invoke	GetOpenFileName,ebx
		assume	ebx:nothing
		or	eax,eax
		jz	notopen
		
		mov	edi,offset filename
		call	GetProjectName
		
		invoke	SetDlgItemText,hWnd,Edit1,offset filename

		invoke GetDlgItem,hWnd,EditBtn
		invoke EnableWindow,eax,1

		invoke GetDlgItem,hWnd,BuildBtn
		invoke EnableWindow,eax,1

		invoke GetDlgItem,hWnd,ExecuteBtn
		invoke EnableWindow,eax,1

		invoke GetDlgItem,hWnd,OptionBtn
		invoke EnableWindow,eax,1
		
;MMF		;close if possible
		Call	CloseMMF
		
		;open new options file
		mov	ebx,ProjectName
		add	ebx,ProjectNameSz
		mov	dword ptr [ebx],OPT
		invoke	CreateFile,offset filename,GENERIC_READ or GENERIC_WRITE,0,0,OPEN_ALWAYS,0,0
		mov	hFile,eax
		invoke	CreateFileMapping,hFile,0,PAGE_READWRITE,0,fSize,0
		mov	fMap,eax
		invoke	MapViewOfFile,fMap,FILE_MAP_WRITE or FILE_MAP_READ,0,0,fSize
		mov	pData,eax
		mov	eax,[eax+4]
		or	eax,eax
		jnz	exist
		invoke	lstrcpy,pData,offset ml
	exist:			
;/MMF
		;virtual key search
		.IF hthread!=0
		invoke	TerminateThread,hthread,eax
		.ENDIF
		invoke	CreateThread,0,0,offset threadproc,0,0,offset junk
		mov	hthread,eax
notopen:
	.ELSEIF ax==EditBtn
		mov	ebx,ProjectName
		add	ebx,ProjectNameSz
		mov	dword ptr [ebx],ASM
		invoke	ShellExecute,hWnd,0,offset filename,0,0,SW_NORMAL
		mov	dword ptr [ebx],RC
		invoke	ShellExecute,hWnd,0,offset filename,0,0,SW_NORMAL

	.ELSEIF ax==BuildBtn
	;выполнение с перенаправлением вывода и ошибок
		;clear window
		invoke	SetDlgItemText,hWnd,Edit2,0
		invoke	UpdateWindow,hWnd
		invoke	FormExecCmd,pData

	.ELSEIF ax==ExecuteBtn
		mov	ebx,ProjectName
		add	ebx,ProjectNameSz
		mov	dword ptr [ebx],EXE
		invoke	ShellExecute,hWnd,0,offset filename,0,0,SW_NORMAL
		cmp	eax,32
		ja	executed
		invoke	MessageBoxA,hWnd,offset compile,offset inf,0
	executed:

	.ELSEIF ax==ShowBtn
		mov	ebx,offset tmp
		assume	ebx:ptr RECT
			invoke	GetDlgItem,hWnd,Edit2
			invoke	GetWindowRect,eax,ebx
			mov	edx,[ebx].bottom
			sub	edx,[ebx].top
			
			invoke	GetWindowRect,hWnd,ebx
			
			mov	eax,[ebx].right
			sub	eax,[ebx].left

			mov	ecx,[ebx].bottom
			sub	ecx,[ebx].top
			
			.IF	ecx<edx
				add	ecx,edx
			.ELSE
				sub	ecx,edx
			.ENDIF
		
			invoke	SetWindowPos,hWnd,0,[ebx].left,[ebx].top,eax,ecx,SWP_SHOWWINDOW

		assume	ebx:nothing
	.ELSEIF ax==OptionBtn
		invoke	CreateThread,0,0,offset OptThreadProc,0,0,offset junk
		mov	OptThread,eax
		ret
	.ELSEIF ax==OkBtn
		.IF OptThread!=0
			invoke	GetDlgItemText,hWnd,OptEdt,pData,fSize
			invoke	EnableWindow,mainhwnd,1
			invoke	SetActiveWindow,mainhwnd

			invoke	TerminateThread,OptThread,0
			;we never be here
		.ENDIF
	.ENDIF
.ELSE
	popad
	mov eax,FALSE
	ret
.ENDIF
	popad
	mov eax,TRUE
	ret
DlgProc endp
;*********************subroutine CloseMMF******************
CloseMMF proc
	invoke	UnmapViewOfFile,pData
	invoke	CloseHandle,fMap
	invoke	CloseHandle,hFile
	ret
CloseMMF endp
;*********************subroutine GetProjectName******************
GetProjectName proc
	xor	eax,eax
	mov	al,"."
	repne	scasb
	dec	edi
	push	edi
	std	;set direction flag
	mov	al,"\"
	repne	scasb
	cld	;clear direction flag
	add	edi,2
	mov	ProjectName,edi
	pop	eax
	sub	eax,edi
	mov	ProjectNameSz,eax
	ret
GetProjectName endp

;*********************subroutine AddNameToStr*********************
AddNameToStr proc
;	esi -> "!"
	push	esi
	mov	esi,ProjectName
	mov	ecx,ProjectNameSz
	rep	movsb
	pop	esi
	ret
AddNameToStr endp

;*********************subroutine GetCommand*********************
GetCommand proc
;	edi -> buffer to put command line
;	esi -> string
;return	in eax	= not 0,(true)if there are lines after returned line
;		= 0,(false)if returned line is the last
FindLoop:
	lodsb
	cmp	al,"!"
	jne	NotPrj
	Call	AddNameToStr
	jmp	short FindLoop
NotPrj:
	or	eax,eax
	jz	toEnd
	cmp	al,0Ah
	je	Clr0Dh

	stosb
	jmp	short FindLoop
Clr0Dh:
	mov	byte ptr [edi][-1],ah
toEnd:
	xchg	ah,al
	stosb
	ret
GetCommand endp

;*********************subroutine FormCmd*********************
FormExecCmd proc lpbuffer:DWORD
	mov	esi,lpbuffer
next:
	mov	edi,offset tmp
	call	GetCommand
	or	eax,eax
	jz	MainExit
	invoke	Exec,offset tmp
	jmp	next
MainExit:	
	invoke	Exec, offset tmp
	ret
FormExecCmd endp

;*********************subroutine Exec*********************
Exec proc lpbuffer:DWORD
;Write Command line to the window
	invoke	GetDlgItem,mainhwnd,Edit2
	mov	ebx,eax
	invoke	SendMessage,ebx,EM_SETSEL,-1,0
	invoke	SendMessage,ebx,EM_REPLACESEL,0,lpbuffer
	;add new line
	call @newline
	db 0Dh,0Ah,0
	@newline: pop eax
	invoke	SendMessage,ebx,EM_REPLACESEL,0,eax
	;/add new line
;/Write Command line to the window

	mov 	sat.niLength,sizeof SECURITY_ATTRIBUTES
	mov 	sat.lpSecurityDescriptor,NULL
	mov 	sat.bInheritHandle,TRUE
	invoke	CreatePipe,addr hRead,addr hWrite,addr sat,NULL

	invoke	RtlZeroMemory,addr startupinfo,sizeof STARTUPINFO
	mov	startupinfo.cb,sizeof STARTUPINFO
	invoke	GetStartupInfo,addr startupinfo
	mov	eax,hWrite
	mov	startupinfo.hStdOutput,eax
	mov	startupinfo.hStdError,eax
	mov	startupinfo.dwFlags,STARTF_USESHOWWINDOW+STARTF_USESTDHANDLES
	mov	startupinfo.wShowWindow,SW_HIDE
	;-------------------------------------------------
	; Create process
	;-------------------------------------------------
	invoke	CreateProcess,NULL,lpbuffer,NULL,NULL,TRUE,NULL,NULL,NULL,addr startupinfo,addr pinfo
	invoke	CloseHandle,hWrite
		.while TRUE
			invoke	RtlZeroMemory,lpbuffer,1024
			invoke	ReadFile,hRead,lpbuffer,1023,addr junk,NULL
			.if eax==NULL
				.break
			.else
				invoke	GetDlgItem,mainhwnd,Edit2
 				mov	ebx,eax
				invoke	SendMessage,ebx,EM_SETSEL,-1,0
				invoke	SendMessage,ebx,EM_REPLACESEL,FALSE,lpbuffer
			.endif
		.endw
	invoke	CloseHandle,hRead
	ret
Exec endp

;*********************subroutine hotkeys*********************
threadproc proc
	invoke	GetCurrentThread
	invoke	SetThreadPriority,eax,THREAD_PRIORITY_LOWEST
threadloop:	
	invoke	GetKeyState,VK_F9
	cmp	eax,0FF00h
	jb	threadproc

	invoke	GetKeyState,VK_CONTROL
	cmp	eax,0FF00h
	jb	@1
	mov	ebx,BuildBtn
	jmp	waitunpress ;VK_F9 unpress
@1:	mov	ebx,ExecuteBtn
waitunpress:
	invoke	GetKeyState,VK_F9
	cmp	eax,0FF00h
	ja	waitunpress

	invoke	DlgProc,mainhwnd,WM_COMMAND,ebx,0
	jmp	threadloop
threadproc endp
end _Start