Česky
Kamil Dudka

FastPad (Assembler)

File detail

Name:DownloadFastPad.asm [Download]
Location: fastpad
Size:33.4 KB
Last modification:2007-08-29 02:14

Source code

;********************************************************************
%include 'C:\PAS\nasm\inc\win32n.inc'
%include 'C:\PAS\nasm\inc\general.mac'
%include 'FastPad.Inc'
 
; Count of bytes allocated for file name, title and ...
%define MAX_PATH			4096
 
; Maximum count of windows opened at one time
%define MAX_WIN_COUNT		256
 
; Import several functions from system dlls
dllimport GetModuleHandle, kernel32.dll, GetModuleHandleA
dllimport ExitProcess, kernel32.dll
dllimport RegisterClassEx, user32.dll, RegisterClassExA
dllimport CreateWindowEx, user32.dll, CreateWindowExA
dllimport ShowWindow, user32.dll
dllimport UpdateWindow, user32.dll
dllimport TranslateMessage, user32.dll
dllimport DispatchMessage, user32.dll, DispatchMessageA
dllimport PostQuitMessage, user32.dll
dllimport GetMessage, user32.dll, GetMessageA
dllimport DefFrameProc, user32.dll, DefFrameProcA
dllimport LoadCursor, user32.dll, LoadCursorA
dllimport FindWindow, user32.dll, FindWindowA
dllimport MessageBox, user32.dll, MessageBoxA
dllimport LoadIcon, user32.dll, LoadIconA
dllimport GetMenu, user32.dll
dllimport GetSubMenu, user32.dll
dllimport SendMessage, user32.dll, SendMessageA
dllimport DefMDIChildProc, user32.dll, DefMDIChildProcA
dllimport LoadAccelerators, user32.dll, LoadAcceleratorsA
dllimport TranslateMDISysAccel, user32.dll
dllimport TranslateAccelerator, user32.dll
dllimport GetProcessHeap, kernel32.dll
dllimport HeapAlloc, kernel32.dll
dllimport HeapFree, kernel32.dll
dllimport SetWindowLong, user32.dll, SetWindowLongA
dllimport GetWindowLong, user32.dll, GetWindowLongA
dllimport SetFocus, user32.dll
dllimport MoveWindow, user32.dll
dllimport GetWindow, user32.dll
dllimport EnumChildWindows, user32.dll
dllimport GetParent, user32.dll
dllimport EnableMenuItem, user32.dll
dllimport IsClipboardFormatAvailable, user32.dll
dllimport GetOpenFileName, comdlg32.dll, GetOpenFileNameA
dllimport GetSaveFileName, comdlg32.dll, GetSaveFileNameA
dllimport SetWindowText, user32.dll, SetWindowTextA
dllimport CreateFontIndirect, gdi32.dll, CreateFontIndirectA
dllimport DeleteObject, gdi32.dll
dllimport CreateFile, kernel32.dll, CreateFileA
dllimport CloseHandle, kernel32.dll
dllimport GetFileSize, kernel32.dll
dllimport ReadFile, kernel32.dll
dllimport WriteFile, kernel32.dll
dllimport GetFileAttributes, kernel32.dll, GetFileAttributesA
dllimport SetFileAttributes, kernel32.dll, SetFileAttributesA
dllimport GetWindowTextLength, user32.dll, GetWindowTextLengthA
dllimport GetWindowText, user32.dll, GetWindowTextA
 
; Document-specific data
struc DOCDATA
	.hWndEdit			resd 1
	.bNeedSave			resd 1
	.szFileName			resb MAX_PATH
	.szTitle			resb MAX_PATH
	.hFont				resd 1
endstruc
 
; Data section
[section .data class=data use32]
	string szAppName,"FastPad"			; Also used for FrameWnd class name
	string szDocClass,"FPDoc"			; Class name for child windows
	string szMDIClient,"MDICLIENT"
	string szEdit,"edit"
	string szFilter,"Text files (*.txt)",0,"*.txt",0,\
					"INI files (*.ini)",0,"*.ini",0,\
					"LOG files (*log)",0,"*.log",0,\
					"Batch files (*.bat)",0,"*.bat",0,\
					"All files (*.*)",0,"*.*",0
	string szExtension,"txt"
	string szUntiled,"Untiled.txt"
	string szAskForSave,"Save changes?"
	string szAbout,"FastPad - simple editor, by Kamil Dudka, mailto: xdudka00@gmail.com"
	string szErrDocOpened,"This document is already opened! Press Retry to choose another file."
	string szErrLoad,"Could not open document!"
	string szErrSave,"Could not save document!" 
	string szErrAttrRO,"File is read-only!"
	string szErrAttrSYS,"File is system-file!"
	string szErrDevel,"Ooooops, this fauture is under construction.."
	string szErrWinLimit,"Ooooops, too many windows opened.."
	string szErrAlloc,"CRITICAL: Out of memory! All data will be lost!"
	string szErrLimit,"Out of range!"
	string szErrInit,"Error during initialization!"
 
	; Global variables
	hInstance			dd 0			; handle instance
	hWnd				dd 0			; Main window hWnd
	hWndMDI				dd 0			; MDI Client hWnd
	hAccel				dd 0			; handle to menu accelerators
	iWndCount			dd 0			; count of opened window
	msg					resb MSG_size	; structure for window message loop
	szFileName			resb MAX_PATH	; global FileName variable
	szTitle				resb MAX_PATH	; global Title varible
 
	; Structure for RegisterClassEx function
	WndClass:
	istruc WNDCLASSEX
		at WNDCLASSEX.cbSize,			dd WNDCLASSEX_size
		at WNDCLASSEX.style,			dd CS_VREDRAW + CS_HREDRAW
		at WNDCLASSEX.lpfnWndProc,		dd AppWndProc
		at WNDCLASSEX.cbClsExtra,		dd 0
		at WNDCLASSEX.cbWndExtra,		dd 0
		at WNDCLASSEX.hInstance,		dd NULL			; Will be rewritten later
		at WNDCLASSEX.hIcon,			dd NULL			; Will be rewritten later
		at WNDCLASSEX.hCursor,			dd NULL			; Will be rewritten later
		at WNDCLASSEX.hbrBackground,	dd COLOR_APPWORKSPACE + 1;
		at WNDCLASSEX.lpszMenuName,		dd IDR_MENU
		at WNDCLASSEX.lpszClassName,	dd szAppName
		at WNDCLASSEX.hIconSm,			dd NULL
	iend
 
	; Structure for create MDICLIENT
	CRClient:
	istruc CLIENTCREATESTRUCT
		at CLIENTCREATESTRUCT.hWindowMenu,	dd NULL		; Will be rewritten later
		at CLIENTCREATESTRUCT.idFirstChild,	dd 50000
	iend
 
	; Structure for create MDI Child Window
	MDICreate:
	istruc MDICREATESTRUCT
		at MDICREATESTRUCT.szClass,			dd szDocClass
		at MDICREATESTRUCT.szTitle,			dd szTitle			; Can be rewritten later
		at MDICREATESTRUCT.hOwner,			dd NULL				; Will be rewritten later
		at MDICREATESTRUCT.x,				dd CW_USEDEFAULT
		at MDICREATESTRUCT.y,				dd CW_USEDEFAULT
		at MDICREATESTRUCT.lx,				dd CW_USEDEFAULT
		at MDICREATESTRUCT.ly,				dd CW_USEDEFAULT
		at MDICREATESTRUCT.style,			dd 0				; Will be rewritten later
		at MDICREATESTRUCT.lParam,			dd 0
	iend
 
	; Structure for OpenFile and SaveFile dialogs
	OFN:
	istruc OPENFILENAME
		at OPENFILENAME.lStructSize,		dd OPENFILENAME_size
		at OPENFILENAME.hWndOwner,			dd NULL				; Will be rewritten later
		at OPENFILENAME.hInstance,			dd NULL
		at OPENFILENAME.lpstrFilter,		dd szFilter
		at OPENFILENAME.lpstrCustomFilter,	dd NULL
		at OPENFILENAME.nMaxCustFilter,		dd 0
		at OPENFILENAME.nFilterIndex,		dd 0
		at OPENFILENAME.lpstrFile,			dd szFileName
		at OPENFILENAME.nMaxFile,			dd MAX_PATH-1
		at OPENFILENAME.lpstrFileTitle,		dd szTitle
		at OPENFILENAME.nMaxFileTitle,		dd MAX_PATH-1
		at OPENFILENAME.lpstrInitialDir,	dd NULL
		at OPENFILENAME.lpstrTitle,			dd NULL
		at OPENFILENAME.Flags,				dd 0
		at OPENFILENAME.nFileOffset,		dw 0
		at OPENFILENAME.nFileExtension,		dw 0
		at OPENFILENAME.lpstrDefExt,		dd szExtension
		at OPENFILENAME.lCustData,			dd 0
		at OPENFILENAME.lpfnHook,			dd NULL
		at OPENFILENAME.lpTemplateName,		dd NULL
	iend
 
	; Structure for CreateFontIndirect function
	LOGF:
	istruc LOGFONT
		at LOGFONT.lfHeight,				dw 16
		at LOGFONT.lfWidth,					dw 0
		at LOGFONT.lfEscapement,			dw 0
		at LOGFONT.lfOrientation,			dw 0
		at LOGFONT.lfWeight,				dw 0
		at LOGFONT.lfItalic,				db 0
		at LOGFONT.lfUnderline,				db 0
		at LOGFONT.lfStrikeOut,				db 0
		at LOGFONT.lfCharSet,				db 0
		at LOGFONT.lfOutPrecision,			db 0
		at LOGFONT.lfClipPrecision,			db 0
		at LOGFONT.lfQuality,				db 0
		at LOGFONT.lfPitchAndFamily,		db 0
		at LOGFONT.lfFaceName,				db "Courier New",0	
	iend
 
; Code section
[section .code class=code use32]
..start:
 
		; Get hInstance for this instance
		invoke GetModuleHandle,NULL
		mov [hInstance], eax
		mov [WndClass + WNDCLASSEX.hInstance], eax
 
		; Check for another instance of FastPad
		invoke FindWindow, szAppName, NULL
		test eax,eax
		jz .ChkAnotherInstance_OK
		invoke MessageBox, NULL, szErrDevel, szAppName, MB_ICONERROR
		jmp .AbnExit
	.ChkAnotherInstance_OK:
 
		; Load Icon And Cursor for main window
		invoke LoadIcon, [hInstance], IDI_ICON_EDITOR
		mov [WndClass + WNDCLASSEX.hIcon], eax
		invoke LoadCursor, NULL, IDC_ARROW
		mov [WndClass + WNDCLASSEX.hCursor],eax
 
		; Register main window class
		invoke RegisterClassEx,WndClass
		test eax, eax
		jz near .ErrInit
 
		; Set Icon for document window
		invoke LoadIcon, [hInstance], IDI_ICON_DOCUMENT
		mov [WndClass + WNDCLASSEX.hIcon], eax
 
		; Register document winodow class
		mov [WndClass + WNDCLASSEX.lpszClassName],	DWORD szDocClass 	; Name of the document class
		mov [WndClass + WNDCLASSEX.lpszMenuName],	DWORD NULL
		mov [WndClass + WNDCLASSEX.lpfnWndProc],	DWORD DocWndProc	; Callback procedure
		mov [WndClass + WNDCLASSEX.cbWndExtra],		DWORD 4				; Space for pointer to user data
		invoke RegisterClassEx, WndClass
		test eax, eax
		jz near .ErrInit
 
		; Load Menu Accelerators
		invoke LoadAccelerators, [hInstance], IDR_MENU_ACCELERATORS
		mov [hAccel], eax
 
		; Create window
		invoke CreateWindowEx,0,szAppName,szAppName,\
			WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,\
			CW_USEDEFAULT, CW_USEDEFAULT,\
			CW_USEDEFAULT, CW_USEDEFAULT,\
			NULL, NULL, [hInstance], NULL
		test eax, eax
		jz near .ErrInit
		mov [hWnd], eax									; Save hWnd to global variable
		mov [OFN + OPENFILENAME.hWndOwner], eax			; Save hWndOwner for FileName dialogs
 
		; Show and redraw the window
		invoke ShowWindow, eax, SW_SHOWDEFAULT
		invoke UpdateWindow, [hWnd]
 
	; Window message loop
	.MessageLoop:
		; Get msg from queue
		invoke GetMessage, msg, NULL, 0, 0
		test eax, eax
		jz near .ExitMsgLoop	; Normal exit
		cmp eax,-1
		jz near .AbnExit		; Error
 
		; MDI Accelerators
		invoke TranslateMDISysAccel, [hWndMDI], msg
		test eax, eax
		jnz .MessageLoop
 
		; My Accelerators
		invoke TranslateAccelerator, [hWnd], [hAccel], msg
		test eax, eax
		jnz .MessageLoop
 
		; Handle msg
		invoke TranslateMessage,msg
		invoke DispatchMessage,msg
		jmp .MessageLoop
 
	.ExitMsgLoop:
		invoke ExitProcess, [msg + MSG.wParam]
 
	; Error during initialization
	.ErrInit:
		invoke MessageBox, NULL, szErrInit, szAppName, MB_ICONERROR
 
	; Abnormal Exit
	.AbnExit:
		invoke MessageBox, NULL, szErrAlloc, szAppName, MB_ICONERROR
		invoke ExitProcess, 1
 
 
; Main window callback procedure
function AppWndProc, AWP_hWnd, AWP_wMsg, AWP_wParam, AWP_lParam
begin
		; msg switch
		mov eax, DWORD [AWP_wMsg]
		cmp eax, WM_INITMENUPOPUP
		je near .AWP_InitMenuPopup
		cmp eax, WM_COMMAND
		je near .AWP_Command
		cmp eax, WM_CREATE
		je near .AWP_Create
		cmp eax, WM_CLOSE
		je near .AWP_Close
		cmp eax, WM_QUERYENDSESSION
		je near .AWP_Close
		cmp eax, WM_DESTROY
		je near .AWP_Destroy
 
	.AWP_DefWndProc:
		; Send unhandled msg to DefWindowProc
		invoke DefFrameProc, [AWP_hWnd], [hWndMDI], [AWP_wMsg], [AWP_wParam], [AWP_lParam]
		return eax
 
	.AWP_Create:
		; Get handle to Window menu
		invoke GetMenu, [AWP_hWnd]
		invoke GetSubMenu, eax, MENU_WND_POS
		mov [CRClient + CLIENTCREATESTRUCT.hWindowMenu], eax
 
		; Create MDICLIENT window
		invoke CreateWindowEx, 0, szMDIClient, NULL, WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,\
			0, 0, 0, 0, [AWP_hWnd], 1, [hInstance], CRClient
		mov [hWndMDI], eax
		jmp .AWP_Finish
 
		; Initialize global variables
		mov [szFileName], byte 0
		mov [szTitle], byte 0
 
	.AWP_InitMenuPopup:
		; Check for child window
		invoke SendMessage, [hWndMDI], WM_MDIGETACTIVE, 0, 0
		test eax, eax
		jz near .AWPI_Disable	; no child window available
 
		push ebx
		mov ebx, eax
		invoke EnableMenuItem, [AWP_wParam], IDM_FILE_SAVEAS, MF_ENABLED
		invoke EnableMenuItem, [AWP_wParam], IDM_EDIT_SELECTALL, MF_ENABLED
		invoke EnableMenuItem, [AWP_wParam], IDM_WINDOW_NEXT, MF_ENABLED
		invoke EnableMenuItem, [AWP_wParam], IDM_WINDOW_TILE, MF_ENABLED
		invoke EnableMenuItem, [AWP_wParam], IDM_WINDOW_CASCADE, MF_ENABLED
		invoke EnableMenuItem, [AWP_wParam], IDM_WINDOW_ARRANGE, MF_ENABLED
		invoke EnableMenuItem, [AWP_wParam], IDM_WINDOW_CLOSE, MF_ENABLED
		invoke EnableMenuItem, [AWP_wParam], IDM_WINDOW_CLOSEALL, MF_ENABLED
 
		; Send Message to child window
		invoke SendMessage, ebx, WM_INITMENUPOPUP, [AWP_wParam], [AWP_lParam]
		pop ebx
		jmp .AWP_Finish
 
	; No child window available
	.AWPI_Disable:
		invoke EnableMenuItem, [AWP_wParam], IDM_FILE_SAVE, MF_GRAYED
		invoke EnableMenuItem, [AWP_wParam], IDM_FILE_SAVEAS, MF_GRAYED
		invoke EnableMenuItem, [AWP_wParam], IDM_EDIT_UNDO, MF_GRAYED
		invoke EnableMenuItem, [AWP_wParam], IDM_EDIT_CUT, MF_GRAYED
		invoke EnableMenuItem, [AWP_wParam], IDM_EDIT_COPY, MF_GRAYED
		invoke EnableMenuItem, [AWP_wParam], IDM_EDIT_PASTE, MF_GRAYED
		invoke EnableMenuItem, [AWP_wParam], IDM_EDIT_SELECTALL, MF_GRAYED
		invoke EnableMenuItem, [AWP_wParam], IDM_WINDOW_NEXT, MF_GRAYED
		invoke EnableMenuItem, [AWP_wParam], IDM_WINDOW_CASCADE, MF_GRAYED
		invoke EnableMenuItem, [AWP_wParam], IDM_WINDOW_TILE, MF_GRAYED
		invoke EnableMenuItem, [AWP_wParam], IDM_WINDOW_ARRANGE, MF_GRAYED
		invoke EnableMenuItem, [AWP_wParam], IDM_WINDOW_CLOSE, MF_GRAYED
		invoke EnableMenuItem, [AWP_wParam], IDM_WINDOW_CLOSEALL, MF_GRAYED
		jmp .AWP_Finish
 
	.AWP_Command:
		; menu item switch
		mov ax, WORD [AWP_wParam]
		cmp ax, IDM_FILE_NEW
		jz near .AWPC_FileNew
		cmp ax, IDM_FILE_OPEN
		jz near .AWPC_FileOpen
		cmp ax, IDM_APP_EXIT
		jz near .AWPC_AppExit
		cmp ax, IDM_WINDOW_NEXT
		jz near .AWPC_WindowNext
		cmp ax, IDM_WINDOW_CASCADE
		jz near .AWPC_WindowCascade
		cmp ax, IDM_WINDOW_TILE
		jz near .AWPC_WindowTile
		cmp ax, IDM_WINDOW_ARRANGE
		jz near .AWPC_WindowArrange
		cmp ax, IDM_WINDOW_CLOSEALL
		jz near .AWPC_WindowCloseAll
		cmp ax, IDM_HELP_ABOUT
		jz near .AWPC_About
 
		; Send msg to child window
		invoke SendMessage, [hWndMDI], WM_MDIGETACTIVE, 0, 0
		test eax,eax
		jz near .AWP_Finish
		invoke SendMessage, eax, WM_COMMAND, [AWP_wParam], [AWP_lParam]
		jmp .AWP_DefWndProc
 
	.AWPC_FileNew:
		; Set Title and FileName
		call strcpy, szFileName, szUntiled, MAX_PATH
		call strcpy, szTitle, szUntiled, MAX_PATH
 
		; Create child window
		call CreateChild
		test eax, eax
		jz near .AWP_WinLimit
 
		; Get ptr to docuemnt-specific data
		invoke GetWindowLong, eax, 0
		push ebx
		mov ebx,eax
		; Initialize document data
		lea eax, [ebx + DOCDATA.szFileName]
		call strcpy, eax, szFileName, MAX_PATH
		lea eax, [ebx + DOCDATA.szTitle]
		call strcpy, eax, szTitle, MAX_PATH
 
		pop ebx
		jmp .AWP_Finish
 
	.AWPC_FileOpen
		; Initalize structure for OpenFile Dialog
		mov [OFN + OPENFILENAME.Flags], DWORD OFN_HIDEREADONLY; | OFN_CREATEPROMPT
 
		; Ask for file name as long as needed
	.AWPCFO_Loop:
		invoke GetOpenFileName, OFN
		test eax, eax
		jz near .AWP_Finish							; Cancel
		invoke GetWindow, [hWndMDI], GW_CHILD
		test eax, eax
		jz .AWPCFO_LoopExit							; No child window
		invoke EnumChildWindows, [hWndMDI], EPMatchFile, szFileName
		test eax, eax
		jnz .AWPCFO_LoopExit						; We got unique file name
		invoke MessageBox, [AWP_hWnd], szErrDocOpened, szFileName, MB_RETRYCANCEL | MB_ICONERROR
		cmp eax, IDCANCEL
		jz near .AWP_Finish							; Cancel
		jmp .AWPCFO_Loop 
	.AWPCFO_LoopExit:
 
		; Create new child window
		call CreateChild
		test eax, eax
		jz near .AWP_WinLimit
		push eax
 
		; Get pointer to document-specific data
		invoke GetWindowLong, eax, 0
		push ebx
		mov ebx, eax
		; Save document-specific data
		lea eax, [ebx + DOCDATA.szFileName]
		call strcpy, eax, szFileName, MAX_PATH
		lea eax, [ebx + DOCDATA.szTitle]
		call strcpy, eax, szTitle, MAX_PATH
		pop ebx	
 
		; Load document text
		mov eax, [esp]
		call DocLoad, eax
		test eax, eax
		jnz .AWPCFO_Error
 
		pop eax
		jmp .AWP_Finish
 
	.AWPCFO_Error:
		invoke MessageBox, [AWP_hWnd], szErrLoad, szFileName, MB_OK | MB_ICONSTOP
 
		; Close document window
		pop eax
		invoke SendMessage, eax, WM_CLOSE, 0, 0
 
		jmp .AWP_Finish
 
	.AWPC_AppExit:
		invoke SendMessage, [AWP_hWnd], WM_CLOSE, 0, 0
		jmp .AWP_Finish
 
	.AWPC_WindowNext:
		invoke SendMessage, [hWndMDI], WM_MDINEXT, 0, 0
		jmp .AWP_Finish
 
	.AWPC_WindowCascade:
		invoke SendMessage, [hWndMDI], WM_MDICASCADE, 0, 0
		jmp .AWP_Finish
 
	.AWPC_WindowTile:
		invoke SendMessage, [hWndMDI], WM_MDITILE, 0, 0
		jmp .AWP_Finish
 
	.AWPC_WindowArrange:
		invoke SendMessage, [hWndMDI], WM_MDIICONARRANGE, 0, 0
		jmp .AWP_Finish
 
	.AWPC_WindowCloseAll:
		; Enumerate child windows using my function EPClose (see bellow)
		invoke EnumChildWindows, [hWndMDI], EPClose, 0
		jmp .AWP_Finish
 
	.AWPC_About:
		invoke MessageBox, [AWP_hWnd], szAbout, szAppName, MB_OK | MB_ICONINFORMATION
		jmp .AWP_Finish
 
	.AWP_Close:
		; We should send WM_QUERYENDSESSION to child windows
		invoke SendMessage, [AWP_hWnd], WM_COMMAND, IDM_WINDOW_CLOSEALL, 0
 
		; Is anybody still here?
		invoke GetWindow, [hWndMDI], GW_CHILD
		test eax, eax
		jnz near .AWP_Finish
		jmp .AWP_DefWndProc
 
	.AWP_WinLimit:
		invoke MessageBox, [AWP_hWnd], szErrWinLimit, szAppName, MB_OK | MB_ICONSTOP
		return 0
 
	.AWP_Destroy:
		invoke PostQuitMessage,0
 
	.AWP_Finish:
	return 0
 
end ;AppWndProc
 
; Document windows callback procedure
function DocWndProc,DWP_hWnd,DWP_wMsg,DWP_wParam,DWP_lParam
var DWP_bMaximized, DWP_iSelBeg, DWP_iSelEnd
begin
		; msg switch
		mov eax,dword [DWP_wMsg]
		cmp eax, WM_SETFOCUS
		jz near .DWP_SetFocus
		cmp eax, WM_SIZE
		jz near .DWP_Size
		cmp eax, WM_INITMENUPOPUP
		jz near .DWP_InitMenuPopup
		cmp eax, WM_COMMAND
		jz near .DWP_Command
		cmp eax, WM_CREATE
		jz near .DWP_Create
		cmp eax, WM_CLOSE
		je near .DWP_Close
		cmp eax, WM_QUERYENDSESSION
		je near .DWP_Close
		cmp eax, WM_DESTROY
		jz near .DWP_Destroy
 
	.DWP_DefWndProc:
		; Send unhandled msg to DefWindowProc
		invoke DefMDIChildProc, [DWP_hWnd], [DWP_wMsg], [DWP_wParam], [DWP_lParam]
		return eax
 
	.DWP_Create:
		; Alocate space for Document-specific data
		invoke GetProcessHeap
		invoke HeapAlloc, eax, 0, DOCDATA_size
		test eax, eax
		jnz .DWP_CreateAllocOK
		invoke MessageBox, [hWnd], szErrAlloc, szAppName, MB_OK | MB_ICONSTOP
		invoke ExitProcess, 1
	.DWP_CreateAllocOK:
		push ebx
		mov ebx, eax 
		; Save pointer to "cbWndExtra"
		invoke SetWindowLong, [DWP_hWnd], 0, eax
 
		; Create EditBox
		invoke CreateWindowEx, 0, szEdit, NULL,\
			WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER |\
			ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,\
			0, 0, 0, 0, [DWP_hWnd], ID_EDIT, [hInstance], NULL
 
		; Save document data
		mov [ebx + DOCDATA.hWndEdit], eax
		mov [ebx + DOCDATA.bNeedSave], DWORD 0
 
		; Terminate string with null character
		mov [ebx + DOCDATA.szFileName], BYTE 0
		mov [ebx + DOCDATA.szTitle], BYTE 0
 
		; Save hWndEdit to stack
		push eax
 
		; Set Font
		invoke CreateFontIndirect, LOGF
		mov [ebx + DOCDATA.hFont], eax
		pop ebx
		invoke SendMessage, ebx, WM_SETFONT, eax, 0
 
		; Set limit of EditBox and Set focus		
		invoke SendMessage, ebx, EM_SETLIMITTEXT, -1, 0
		invoke SetFocus, ebx
 
		pop ebx
		jmp .DWP_Finish
 
	.DWP_InitMenuPopup:
		; Is window maximized?
		lea eax, [DWP_bMaximized]
		invoke SendMessage, [hWndMDI], WM_MDIGETACTIVE, 0, eax
		mov eax, [DWP_bMaximized]
		test eax, eax
		mov eax, [DWP_lParam]
		jz .DWPI_NotMaximized
		; Window is maximized ==> we should count the icon on the left
		dec eax
	.DWPI_NotMaximized:
		; Popup Menu switch
		test eax,eax
		jz .DWPI_File
		dec eax
		jz .DWPI_Edit
		jmp .DWP_DefWndProc
 
	; Init menu Popup "File" - menu item "Save"
	.DWPI_File:
		invoke GetWindowLong, [DWP_hWnd], 0
		mov eax, [eax + DOCDATA.bNeedSave]
		test eax, eax
		jnz .DWPIF_NeedSave
		invoke EnableMenuItem, [DWP_wParam], IDM_FILE_SAVE, MF_GRAYED
		jmp .DWP_Finish
	.DWPIF_NeedSave:
		invoke EnableMenuItem, [DWP_wParam], IDM_FILE_SAVE, MF_ENABLED
		jmp .DWP_Finish
 
	; Ini menu Popup "Edit"
	.DWPI_Edit:
		push ebx
		push ecx
		invoke GetWindowLong, [DWP_hWnd], 0
		mov eax, [eax + DOCDATA.hWndEdit]
		push eax
		; Test if "undo" is possible - menu item "undo"
		invoke SendMessage, eax, EM_CANUNDO, 0, 0
		test eax, eax
		jnz .DWPIE_CanUndo
		invoke EnableMenuItem, [DWP_wParam], IDM_EDIT_UNDO, MF_GRAYED
		jmp .DWPIE_TestPaste
	.DWPIE_CanUndo:
		invoke EnableMenuItem, [DWP_wParam], IDM_EDIT_UNDO, MF_ENABLED
	.DWPIE_TestPaste:
 
		; Test if "paste" is possible - menu item "paste"
		invoke IsClipboardFormatAvailable, CF_TEXT
		test eax, eax
		jnz .DWPIE_CanPaste
		invoke EnableMenuItem, [DWP_wParam], IDM_EDIT_PASTE, MF_GRAYED
		jmp .DWPIE_TestSel
	.DWPIE_CanPaste:
		invoke EnableMenuItem, [DWP_wParam], IDM_EDIT_PASTE, MF_ENABLED
	.DWPIE_TestSel:
 
		; Test if "cut" and "copy" are possible
		pop ecx
		lea eax, [DWP_iSelBeg]
		lea ebx, [DWP_iSelEnd]
		invoke SendMessage, ecx, EM_GETSEL, eax, ebx
		mov eax, [DWP_iSelBeg]
		cmp eax, [DWP_iSelEnd]
		jnz .DWPIE_SelAvl
		mov ebx, MF_GRAYED
		jmp .DWPIE_Finish
	.DWPIE_SelAvl:
		mov ebx, MF_ENABLED
	.DWPIE_Finish:
		invoke EnableMenuItem, [DWP_wParam], IDM_EDIT_CUT, ebx
		invoke EnableMenuItem, [DWP_wParam], IDM_EDIT_COPY, ebx
 
		pop ecx
		pop ebx
		jmp .DWP_Finish
 
	.DWP_Command:
		; Menu Item switch
		mov ax, [DWP_wParam]
		cmp ax, IDM_FILE_SAVE
		jz near .DWPC_FileSave
		cmp ax, IDM_FILE_SAVEAS
		jz near .DWPC_FileSaveAs
		cmp ax, IDM_EDIT_UNDO
		jz near .DWPC_EditUndo
		cmp ax, IDM_EDIT_CUT
		jz near .DWPC_EditCut
		cmp ax, IDM_EDIT_COPY
		jz near .DWPC_EditCopy
		cmp ax, IDM_EDIT_PASTE
		jz near .DWPC_EditPaste
		cmp ax, IDM_EDIT_SELECTALL
		jz near .DWPC_EditSelectAll
		cmp ax, IDM_WINDOW_CLOSE
		jz near .DWPC_WindowClose
		cmp ax, ID_EDIT				; msg from EditBox
		jz near .DWPC_EditBox
		jmp .DWP_DefWndProc
 
	.DWPC_FileSave:
		; Get ptr to document data
		invoke GetWindowLong, [DWP_hWnd], 0
		push ebx
		mov ebx, eax
 
		; Test wether save existing file or create new
		lea eax, [ebx + DOCDATA.szFileName]
		call strcmp, eax, szUntiled
		test eax, eax
		jnz .DWPCFS_NotNew
		; Create new file - invoke SaveAs Dialog
		invoke SendMessage, [DWP_hWnd], WM_COMMAND, IDM_FILE_SAVEAS, 0
		pop ebx
		return eax
 
	; Save existing file
	.DWPCFS_NotNew:
		lea eax, [ebx + DOCDATA.szFileName]
		call DocSave, [DWP_hWnd], eax
		test eax, eax
		jnz .DWPCFS_Error
		mov [ebx + DOCDATA.bNeedSave], DWORD 0
		pop ebx
		return 1
 
	; Error during save
	.DWPCFS_Error:
		lea eax, [ebx + DOCDATA.szFileName]
		invoke MessageBox, [DWP_hWnd], szErrSave, eax, MB_OK
		pop ebx
		return 0
 
	.DWPC_FileSaveAs:
		; Get ptr to document data
		invoke GetWindowLong, [DWP_hWnd], 0
		push ebx
		mov ebx, eax
 
		; Initialize SaveFile Dialog
		lea eax, [ebx + DOCDATA.szFileName]
		call strcpy, szFileName, eax, MAX_PATH
		mov [OFN + OPENFILENAME.Flags], DWORD OFN_OVERWRITEPROMPT
 
		; Invoke SaveFile Dialog
		invoke GetSaveFileName, OFN
		test eax, eax
		jz near .DWPCSFA_Finish					; Cancel
 
		; Save document text
		call DocSave, [DWP_hWnd], szFileName
		test eax, eax
		jnz .DWPCSFA_Error
 
		; Synchronize document-specific data
		lea eax, [ebx + DOCDATA.szFileName]
		call strcpy, eax, szFileName, MAX_PATH
		lea eax, [ebx + DOCDATA.szTitle]
		call strcpy, eax, szTitle, MAX_PATH
 
		mov [ebx + DOCDATA.bNeedSave], DWORD 0
 
		; Actualize window title
		invoke SetWindowText, [DWP_hWnd], szTitle
 
		pop ebx
		return 1	
 
	; Error during SaveAs
	.DWPCSFA_Error:
		invoke MessageBox, [DWP_hWnd], szErrSave, szFileName, MB_OK | MB_ICONERROR
 
	; SaveAs normal exit
	.DWPCSFA_Finish:
		pop ebx
		jmp .DWP_Finish
 
	.DWPC_EditUndo
		invoke GetWindowLong, [DWP_hWnd], 0
		invoke SendMessage, [eax + DOCDATA.hWndEdit], WM_UNDO, 0, 0
		jmp .DWP_Finish
 
	.DWPC_EditCut
		invoke GetWindowLong, [DWP_hWnd], 0
		invoke SendMessage, [eax + DOCDATA.hWndEdit], WM_CUT, 0, 0
		jmp .DWP_Finish
 
	.DWPC_EditCopy
		invoke GetWindowLong, [DWP_hWnd], 0
		invoke SendMessage, [eax + DOCDATA.hWndEdit], WM_COPY, 0, 0
		jmp .DWP_Finish
 
	.DWPC_EditPaste
		invoke GetWindowLong, [DWP_hWnd], 0
		invoke SendMessage, [eax + DOCDATA.hWndEdit], WM_PASTE, 0, 0
		jmp .DWP_Finish
 
	.DWPC_EditSelectAll
		invoke GetWindowLong, [DWP_hWnd], 0
		invoke SendMessage, [eax + DOCDATA.hWndEdit], EM_SETSEL, 0, -1
		jmp .DWP_Finish
 
	.DWPC_WindowClose:
		invoke SendMessage, [DWP_hWnd], WM_CLOSE, 0, 0
		jmp .DWP_Finish
 
	; Message from EditBox
	.DWPC_EditBox:
		mov eax, [DWP_lParam]
		test eax, eax
		jz near .DWP_DefWndProc
		; EditBox msg switch
		mov ax, [DWP_wParam + 2]
		cmp ax, EN_UPDATE
		je .DWPCE_Update
		cmp ax, EN_ERRSPACE
		je .DWPCE_Limit
		cmp ax, EN_MAXTEXT
		je .DWPCE_Limit
		jmp .DWP_DefWndProc
 
	; Update msg from EditBox
	.DWPCE_Update:
		invoke GetWindowLong, [DWP_hWnd], 0
		mov [eax + DOCDATA.bNeedSave], DWORD 1
		jmp .DWP_Finish
 
	; Error msg from EditBox
	.DWPCE_Limit:
		invoke MessageBox, [DWP_hWnd], szErrLimit, szAppName, MB_OK | MB_ICONSTOP
		jmp .DWP_Finish
 
	.DWP_SetFocus:
		; Set Focus to EditBox
		invoke GetWindowLong, [DWP_hWnd], 0
		invoke SetFocus, [eax + DOCDATA.hWndEdit]
		jmp .DWP_DefWndProc
 
	.DWP_Size:
		; Set size of the EditBox
		invoke GetWindowLong, [DWP_hWnd], 0
		push edx
 
		push 1
		xor edx,edx
		mov dx, [DWP_lParam + 2]
		push edx
		xor edx,edx
		mov dx, [DWP_lParam]
		push edx
		invoke MoveWindow, [eax + DOCDATA.hWndEdit], 0, 0
 
		pop edx
		jmp .DWP_DefWndProc
 
	; Also WM_QUERYENDSESSION
	.DWP_Close:
		; Does the document need to be saved?
		invoke GetWindowLong, [DWP_hWnd], 0
		mov eax, [eax + DOCDATA.bNeedSave]
		test eax, eax
		jz near .DWP_DefWndProc
		; Ask for save...
		invoke GetWindowLong, [DWP_hWnd], 0
		add eax, DOCDATA.szFileName
		invoke MessageBox, [DWP_hWnd], szAskForSave, eax, MB_YESNOCANCEL | MB_ICONQUESTION
		cmp eax, IDCANCEL
		je near .DWP_Finish
		cmp eax, IDYES
		je .DWP_CloseSave
		jmp .DWP_DefWndProc
 
	.DWP_CloseSave:
		; Send "save" command to this wnd
		invoke SendMessage, [DWP_hWnd], WM_COMMAND, IDM_FILE_SAVE, 0
		test eax, eax
		jz near .DWP_Finish
		jmp .DWP_DefWndProc
 
	.DWP_Destroy
		; Get ptr to document data
		invoke GetWindowLong, [DWP_hWnd], 0
		push ebx
		mov ebx, eax
 
		; Delete font
		invoke DeleteObject, [ebx + DOCDATA.hFont]
 
		; Free space for document-specific data
		; Nobody should ponit to it now
		invoke GetProcessHeap
		invoke HeapFree, eax, 0, ebx
 
		dec DWORD [iWndCount]
 
		pop ebx
		jmp .DWP_DefWndProc 
 
	.DWP_Finish:
	return 0
end ;DocWndProc
 
; Close child windows using WM_QUERYENDSESSION
function EPClose, EPC_hWnd, EPC_lParam
begin
		; Restore native window size
		invoke GetParent, [EPC_hWnd]
		push ebx
		mov ebx, eax
		invoke SendMessage, ebx, WM_MDIRESTORE, [EPC_hWnd], 0
 
		; Ask child window for exit
		invoke SendMessage, [EPC_hWnd], WM_QUERYENDSESSION, 0, 0
		test eax, eax
		jz .EPC_Finish
 
		; Close the child window
		invoke SendMessage, ebx, WM_MDIDESTROY, [EPC_hWnd], 0
 
	.EPC_Finish:
		pop ebx
		return 1
end
 
; Create child window
; Several global variables should be set.. Return hWnd of child window..
CreateChild:
		; Test for windows count limit
		cmp DWORD [iWndCount], MAX_WIN_COUNT
		jl .CC_LimitOK
		xor eax, eax
		ret
	.CC_LimitOK:
		inc DWORD [iWndCount]
 
		; Is here any child window?
		invoke SendMessage, [hWndMDI], WM_MDIGETACTIVE, 0, 0
		test eax, eax
		jz .CC_FirstChild
		; Create new window with normal size
		mov [MDICreate + MDICREATESTRUCT.style], DWORD 0
		jmp .CC_CreateChild
	.CC_FirstChild:
		; Create new window maximized (1st window)
		mov [MDICreate + MDICREATESTRUCT.style], DWORD WS_MAXIMIZE
	.CC_CreateChild
		; Create window now
		invoke SendMessage, [hWndMDI], WM_MDICREATE, 0, MDICreate
	ret
 
; Look for document with same FileName as lParam
function EPMatchFile, EPMF_hWnd, EPMF_lParam
begin
		; Test for valid hWnd
		mov eax, [EPMF_hWnd]
		test eax, eax
		jz near .EPMF_Finish
 
		; Test for WndProc
		invoke GetWindowLong, [EPMF_hWnd], GWL_WNDPROC
		cmp eax, DocWndProc
		jnz .EPMF_Finish
 
		; Get ptr to document data
		invoke GetWindowLong, [EPMF_hWnd], 0
 
		; Compare FileName
		lea eax, [eax + DOCDATA.szFileName]
		call strcmp, eax, [EPMF_lParam]
		test eax, eax
		jnz .EPMF_Finish
 
		; FileName found
		return 0		
 
	.EPMF_Finish:
		return 1
end
 
; Load document text
; Several data structures should be initialized
function DocLoad, DL_hWnd
var DL_hFile, DL_iLength, DL_pBuff, DL_cbRead
begin
		; Get pointer to document-specific data
		invoke GetWindowLong, [DL_hWnd], 0
		push ebx
		mov ebx, eax
 
		; Open File
		lea eax, [ebx + DOCDATA.szFileName]
		invoke CreateFile, eax, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM, NULL
		cmp eax, INVALID_HANDLE_VALUE
		jz near .DL_ErrOpenFile
		mov [DL_hFile], eax
 
		; Get file size
		invoke GetFileSize, eax, NULL
		inc eax		; one byte for zero character
		mov [DL_iLength], eax
 
		; Alloc buffer
		invoke GetProcessHeap
		invoke HeapAlloc, eax, 0, [DL_iLength]
		test eax, eax
		jz .DL_ErrAlloc
		mov [DL_pBuff], eax
 
		; Read data from file
		dec DWORD [DL_iLength]
		lea eax, [DL_cbRead]
		invoke ReadFile, [DL_hFile], [DL_pBuff], [DL_iLength], eax, NULL
 
		; Close File
		invoke CloseHandle, [DL_hFile]
 
		; End with zero character
		mov eax, [DL_pBuff]
		add eax, [DL_iLength]
		mov [eax], BYTE 0
 
		; Load text to document window
		invoke SetWindowText, [ebx + DOCDATA.hWndEdit], [DL_pBuff]
		pop ebx
 
		; Free buffer
		invoke GetProcessHeap
		invoke HeapFree, eax, 0, [DL_pBuff]
 
		return 0
 
	; Could not open file
	.DL_ErrOpenFile:
		pop ebx
		return -1
 
	; Could not allocate buffer
	.DL_ErrAlloc:
		invoke CloseHandle, [DL_hFile]
		pop ebx
		return -1
end	; DocLoad
 
; Save document text to file DS_szFileName
function DocSave, DS_hWnd, DS_szFileName
var DS_dwFileAttr, DS_hFile, DS_iLength, DS_pBuff, DS_cbWrite
begin
 
		; Get File attributes
		invoke GetFileAttributes, [DS_szFileName]
		mov [DS_dwFileAttr], eax
		inc eax
		jnz .DS_FileExist
		; New file is being created
		mov [DS_dwFileAttr], DWORD FILE_ATTRIBUTE_NORMAL
		jmp .DS_AttrOK
 
	.DS_FileExist
		; Check if file is ReadOnly
		test [DS_dwFileAttr], DWORD FILE_ATTRIBUTE_READONLY
		jz .DS_ARO_OK
		; File is ReadOnly
		invoke MessageBox, [DS_hWnd], szErrAttrRO, [DS_szFileName], MB_OKCANCEL | MB_ICONWARNING | MB_DEFBUTTON2
		cmp eax, IDCANCEL
		je near .DS_ErrAttr
 
	.DS_ARO_OK:
		; Check if file is SystemFile
		test [DS_dwFileAttr], DWORD FILE_ATTRIBUTE_SYSTEM
		jz .DS_ASYS_OK
		; File is system file
		invoke MessageBox, [DS_hWnd], szErrAttrSYS, [DS_szFileName], MB_OKCANCEL | MB_ICONWARNING | MB_DEFBUTTON2
		cmp eax, IDCANCEL
		je near .DS_ErrAttr
 
	.DS_ASYS_OK:
		; Temporarry reset attributes to Normal
		invoke SetFileAttributes, [DS_szFileName], FILE_ATTRIBUTE_NORMAL		
 
	.DS_AttrOK:
		; Open or create file
		invoke CreateFile, [DS_szFileName], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, [DS_dwFileAttr], NULL
		cmp eax, INVALID_HANDLE_VALUE
		jz near .DS_ErrOpenFile
		mov [DS_hFile], eax
 
		; Get pointer to document-specific data
		invoke GetWindowLong, [DS_hWnd], 0
		push ebx
		mov ebx, eax
 
		; Get Length of document text
		invoke GetWindowTextLength, [ebx + DOCDATA.hWndEdit]
		inc eax
		mov [DS_iLength], eax
 
		; Alloc buffer
		invoke GetProcessHeap
		invoke HeapAlloc, eax, 0, [DS_iLength]
		test eax, eax
		jz .DS_ErrAlloc
		mov [DS_pBuff], eax
 
		; Get document text
		invoke GetWindowText, [ebx + DOCDATA.hWndEdit], [DS_pBuff], [DS_iLength]
		dec DWORD [DS_iLength]
 
		; Write text to file
		lea eax, [DS_cbWrite]
		invoke WriteFile, [DS_hFile], [DS_pBuff], [DS_iLength], eax, NULL
 
		; Close file		
		invoke CloseHandle, [DS_hFile]
 
		; Free buffer
		invoke GetProcessHeap
		invoke HeapFree, eax, 0, [DS_pBuff]
 
		; Normal Exit
		pop ebx
		return 0
 
	; User is worried :-)
	.DS_ErrAttr:
		return -1
 
	; Could not open file
	.DS_ErrOpenFile:
		invoke SetFileAttributes, [DS_szFileName], [DS_dwFileAttr]
		return -1
 
	; Could not allocate buffer
	.DS_ErrAlloc:
		invoke CloseHandle, [DL_hFile]
		invoke SetFileAttributes, [DS_szFileName], [DS_dwFileAttr]
		pop ebx
		return -1
end
 
 
; strcmp()
function strcmp, strcmp_dest, strcmp_src
begin
		push esi
		push edi
		push edx
		mov edi, [strcmp_dest]
		mov esi, [strcmp_src]
		xor edx, edx
 
 
	.strcmp_Loop:
		xor al,al		; al = 0
		; Compare src for zero
		cmp al,[esi]
		je .strcmp_LoopEnd
		; Compare dest for zero
		cmp al,[edi]
		je .strcmp_LoopEnd
 
		; Compare (src ?? dest)
		mov al,[edi]
		cmp al,[esi]
		jbe .strcmp_NotSrc
		; dest > src
		inc edx
		jmp .strcmp_Finish
	.strcmp_NotSrc:
		jae .strcmp_NotDest
		; dest < src
		dec edx
		jmp .strcmp_Finish
	.strcmp_NotDest:
		; Go to next char
		inc esi
		inc edi
		jmp .strcmp_Loop
	.strcmp_LoopEnd:
		; Compare strlen of src and dest
		mov al,[edi]
		cmp al,[esi]
		jbe .strcmp_NotLen
		; dest > src
		inc edx
		jmp .strcmp_Finish
	.strcmp_NotLen:
		jae .strcmp_Finish
		; src < dec
		dec edx
	.strcmp_Finish:
 
		; Save return value
		mov eax,edx
		pop edx
		pop edi
		pop esi
return eax
end
 
; strcpy ()
; 1. parameter - dest
; 2. parameter - src
; 3. parameter - size of dest array
; return 0 if copy whole string
function strcpy, strcpy_dest, strcpy_src, strcpy_max
begin
		push esi
		mov esi, [strcpy_src]
 
		push edi
		mov edi, [strcpy_dest]
 
		push ecx
		mov ecx, [strcpy_max]
 
		xor eax, eax
 
	.strcpy_Loop:
		; copy byte
		mov al, [esi]
		mov [edi], al
 
		; test for zero
		test al, al
		jz .strcpy_LoopExit
 
		; increment index registers
		inc esi
		inc edi
 
		; main loop
		loop .strcpy_Loop
	.strcpy_LoopExit:	
 
		pop ecx
		pop edi
		pop esi
 
return eax
end