;@echo off
;goto make

echo
	echo -----------------
IFDEF DEBUG
	echo | DEBUG Build   |
ELSE
	echo | RELEASE Build |
ENDIF
	echo -----------------
echo

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
;  Written by Four-F (four-f@mail.ru)
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.386
.model flat, stdcall
option casemap:none

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                  I N C L U D E   F I L E S                                        
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

include \masm32\include\windows.inc

include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\comctl32.inc
include \masm32\include\gdi32.inc
include \masm32\include\advapi32.inc
include \masm32\include\msimg32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\comctl32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\advapi32.lib
includelib \masm32\lib\msimg32.lib

include \masm32\Macros\Strings.mac
include memory.asm
include MaskedEdit.asm
include htodw.asm


;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                 S T R U C T U R E S                                               
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

DIMENSION STRUCT
	Pos	POINT	<>
	Siz	_SIZE	<>
DIMENSION ENDS

MNEMONIC STRUCT
	ioctl	DWORD	?
	lpstr	LPSTR	?
MNEMONIC ENDS

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                         F U N C T I O N S   P R O T O T Y P E S                                   
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

DlgProc	proto :HWND, :UINT, :WPARAM, :LPARAM

externdef g_aszMnemonics:PTR MNEMONIC
externdef g_cbaMnemonics:DWORD

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                        M A C R O S                                                
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

$invoke MACRO vars:VARARG
     invoke vars
     EXITM <eax>
ENDM

mrm MACRO Des:REQ, Sor:REQ
	mov eax, Sor
	mov Des, eax
ENDM

$LOWORD MACRO dwVar:REQ
	IFDIFI <dwVar>, <eax>	;; don't move eax onto itself
		mov eax, dwVar
	ENDIF
	and eax, 0FFFFh
	EXITM <eax>
ENDM

$HIWORD MACRO dwVar:REQ
	IFDIFI <dwVar>, <eax>	;; don't move eax onto itself
		mov eax, dwVar
	ENDIF
	shr eax, 16
	EXITM <eax>
ENDM

date MACRO
local pos, month

	;; Day
	pos = 1
	% FORC chr, @Date
		IF (pos EQ 4) OR (pos EQ 5)
			db "&chr"
		ENDIF
		pos = pos + 1
	ENDM

	;; Month
	pos = 1
	% FORC chr, @Date
		IF (pos EQ 1)
			month TEXTEQU @SubStr(%@Date, 1 , 2)
			IF month EQ 01
				db " Jan "	
			ELSEIF month EQ 02
				db " Feb "	
			ELSEIF month EQ 03
				db " Mar "	
			ELSEIF month EQ 04
				db " Apr "	
			ELSEIF month EQ 05
				db " May "	
			ELSEIF month EQ 06
				db " Jun "	
			ELSEIF month EQ 07
				db " Jul "	
			ELSEIF month EQ 08
				db " Aug "	
			ELSEIF month EQ 09
				db " Sep "	
			ELSEIF month EQ 10
				db " Oct "	
			ELSEIF month EQ 11
				db " Nov "	
			ELSEIF month EQ 12
				db " Dec "	
			ENDIF
		ENDIF
		pos = pos + 1
	ENDM

	;; Year
	db "20"
	pos = 1
	% FORC chr, @Date
		IF (pos EQ 7) OR (pos EQ 8)
			db "&chr"
		ENDIF
		pos = pos + 1
	ENDM

ENDM

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                      E Q U A T E S                                                
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

IDD_MAIN		equ	1000

IDE_IOCTL		equ 1001
IDE_MNEMONIC	equ 1002
IDE_DEVICE		equ 1003
IDE_FUNCTION	equ 1004
IDE_METHOD		equ 1005
IDE_ACCESS		equ 1006
IDE_BITS		equ 1007

IDC_RECOGNIZES_XXX_MNEMONICS equ 1008

IDM_ABOUT		equ 2000

IDI_ICON		equ 3000
IDI_BMP			equ 3001

xBmp			= 77				; X of bitmap
yBmp			= 235

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                  R E A D O N L Y  D A T A                                         
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.const

CTA0 "%d", g_szDec
CTA0 "0x%X", g_szHex
CTA0 "0x%08X", g_szHex08

szAbout						db "About...", 0
szWrittenBy					db "I/O Control Code Decoder v1.2", 0Ah, 0Dh
							db "Compiled on "
							date
							db 0Ah, 0Dh, 0Ah, 0Dh
							db "Written by Four-F <four-f@mail.ru>", 0

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                              I N I T I A L I Z E D  D A T A                                       
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

POINTERS SEGMENT READONLY PUBLIC USE32 'CONST'

g_aszDeviceTypes	label LPSTR
LPSTR	$CTA0("0")
LPSTR	$CTA0("FILE_DEVICE_BEEP")					; 01
LPSTR	$CTA0("FILE_DEVICE_CD_ROM")					; 02
LPSTR	$CTA0("FILE_DEVICE_CD_ROM_FILE_SYSTEM")		; 03
LPSTR	$CTA0("FILE_DEVICE_CONTROLLER ")			; 04
LPSTR	$CTA0("FILE_DEVICE_DATALINK ")				; 05
LPSTR	$CTA0("FILE_DEVICE_DFS")					; 06
LPSTR	$CTA0("FILE_DEVICE_DISK")					; 07
LPSTR	$CTA0("FILE_DEVICE_DISK_FILE_SYSTEM")		; 08
LPSTR	$CTA0("FILE_DEVICE_FILE_SYSTEM")			; 09
LPSTR	$CTA0("FILE_DEVICE_INPORT_PORT")			; 0A
LPSTR	$CTA0("FILE_DEVICE_KEYBOARD")				; 0B
LPSTR	$CTA0("FILE_DEVICE_MAILSLOT ")				; 0C
LPSTR	$CTA0("FILE_DEVICE_MIDI_IN")				; 0D
LPSTR	$CTA0("FILE_DEVICE_MIDI_OUT")				; 0E
LPSTR	$CTA0("FILE_DEVICE_MOUSE")					; 0F
LPSTR	$CTA0("FILE_DEVICE_MULTI_UNC_PROVIDER")		; 10
LPSTR	$CTA0("FILE_DEVICE_NAMED_PIPE")				; 11
LPSTR	$CTA0("FILE_DEVICE_NETWORK")				; 12
LPSTR	$CTA0("FILE_DEVICE_NETWORK_BROWSER")		; 13
LPSTR	$CTA0("FILE_DEVICE_NETWORK_FILE_SYSTEM")	; 14
LPSTR	$CTA0("FILE_DEVICE_NULL")					; 15
LPSTR	$CTA0("FILE_DEVICE_PARALLEL_PORT")			; 16
LPSTR	$CTA0("FILE_DEVICE_PHYSICAL_NETCARD")		; 17
LPSTR	$CTA0("FILE_DEVICE_PRINTER")				; 18
LPSTR	$CTA0("FILE_DEVICE_SCANNER")				; 19
LPSTR	$CTA0("FILE_DEVICE_SERIAL_MOUSE_PORT")		; 1A
LPSTR	$CTA0("FILE_DEVICE_SERIAL_PORT")			; 1B
LPSTR	$CTA0("FILE_DEVICE_SCREEN")					; 1C
LPSTR	$CTA0("FILE_DEVICE_SOUND")					; 1D
LPSTR	$CTA0("FILE_DEVICE_STREAMS")				; 1E
LPSTR	$CTA0("FILE_DEVICE_TAPE")					; 1F
LPSTR	$CTA0("FILE_DEVICE_TAPE_FILE_SYSTEM")		; 20
LPSTR	$CTA0("FILE_DEVICE_TRANSPORT")				; 21
LPSTR	$CTA0("FILE_DEVICE_UNKNOWN")				; 22
LPSTR	$CTA0("FILE_DEVICE_VIDEO ")					; 23
LPSTR	$CTA0("FILE_DEVICE_VIRTUAL_DISK")			; 24
LPSTR	$CTA0("FILE_DEVICE_WAVE_IN")				; 25
LPSTR	$CTA0("FILE_DEVICE_WAVE_OUT")				; 26
LPSTR	$CTA0("FILE_DEVICE_8042_PORT")				; 27
LPSTR	$CTA0("FILE_DEVICE_NETWORK_REDIRECTOR")		; 28
LPSTR	$CTA0("FILE_DEVICE_BATTERY")				; 29
LPSTR	$CTA0("FILE_DEVICE_BUS_EXTENDER")			; 2A FILE_DEVICE_GAMEENUM
LPSTR	$CTA0("FILE_DEVICE_MODEM")					; 2B
LPSTR	$CTA0("FILE_DEVICE_VDM")					; 2C
LPSTR	$CTA0("FILE_DEVICE_MASS_STORAGE")			; 2D
LPSTR	$CTA0("FILE_DEVICE_SMB")					; 2E
LPSTR	$CTA0("FILE_DEVICE_KS")						; 2F
LPSTR	$CTA0("FILE_DEVICE_CHANGER")				; 30
LPSTR	$CTA0("FILE_DEVICE_SMARTCARD")				; 31
LPSTR	$CTA0("FILE_DEVICE_ACPI")					; 32
LPSTR	$CTA0("FILE_DEVICE_DVD")					; 33
LPSTR	$CTA0("FILE_DEVICE_FULLSCREEN_VIDEO")		; 34
LPSTR	$CTA0("FILE_DEVICE_DFS_FILE_SYSTEM")		; 35
LPSTR	$CTA0("FILE_DEVICE_DFS_VOLUME")				; 36
LPSTR	$CTA0("FILE_DEVICE_SERENUM")				; 37
LPSTR	$CTA0("FILE_DEVICE_TERMSRV")				; 38
LPSTR	$CTA0("FILE_DEVICE_KSEC")					; 39
g_cbaDeviceTypes	equ $-g_aszDeviceTypes

g_aszMethods	label LPSTR
LPSTR	$CTA0("METHOD_BUFFERED")					; 0
LPSTR	$CTA0("METHOD_IN_DIRECT")					; 1
LPSTR	$CTA0("METHOD_OUT_DIRECT")					; 2
LPSTR	$CTA0("METHOD_NEITHER")						; 3
g_cbaMethods	equ $-g_aszMethods

g_aszAccesses	label LPSTR
LPSTR	$CTA0("FILE_ANY_ACCESS")					; 0
LPSTR	$CTA0("FILE_READ_ACCESS")					; 1
LPSTR	$CTA0("FILE_WRITE_ACCESS")					; 2
LPSTR	$CTA0("FILE_READ_ACCESS + FILE_WRITE_ACCESS"); 3
g_cbaAccesses	equ $-g_aszAccesses

POINTERS ENDS

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                              I N I T I A L I Z E D  D A T A                                       
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.data

g_BmpDimension			DIMENSION	<{xBmp, yBmp},{ , }>

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                              U N I N I T I A L I Z E D  D A T A                                   
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.data?

g_hInstance				HINSTANCE	?

g_hDlg					HWND		?

g_hwndEditIoctl			HWND		?
g_hwndSpinFunction		HWND		?
g_hwndSpinMethod		HWND		?
g_hwndSpinAccess		HWND		?

g_hwndStaticMnemonics	HWND		?
g_hwndEditMnemonic		HWND		?

g_hFontOld1				HFONT		?
g_hFontBold				HFONT		?

g_hFontOld2				HFONT		?
g_hFontCourier			HFONT		?

g_hbmp					HBITMAP		?
g_hMemDC				HDC			?

;g_hwndBits				HWND		?

IFDEF DEBUG
g_hConsoleInput			HANDLE		?
g_hConsoleOutput		HANDLE		?
ENDIF

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                       C O D E                                                     
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.code

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                   DrawTransparent                                                 
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

DrawTransparent proc uses esi hDC:HDC, hMemDC:HDC, hbmp:HBITMAP, pBmpDimension:LPVOID

local hbmpOld:HBITMAP

	mov hbmpOld, $invoke(SelectObject, hMemDC, hbmp)

	mov esi, pBmpDimension
	assume esi:ptr DIMENSION	
	; Get ROLORREF of left-top most pixel to use it as transparent
	invoke GetPixel, hMemDC, 0, 0
	push eax						; crTransparent
	push [esi].Siz.y				; nHeightSrc
	push [esi].Siz.x				; nWidthSrc
	push 0							; nYOriginSrc
	push 0							; nXOriginSrc
	push hMemDC						; hdcSrc
	push [esi].Siz.y				; hHeightDest
	push [esi].Siz.x				; nWidthDest
	push [esi].Pos.y				; nYOriginDest
	push [esi].Pos.x				; nXOriginDest
	push hDC						; hdcDest
	call TransparentBlt
	assume esi:nothing

	invoke SelectObject, hMemDC, hbmpOld

	ret

DrawTransparent endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                    DwToBinStr                                                     
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

DwToBinStr proc uses esi dwVal:DWORD, pBuffer:LPVOID, uBits:UINT

	mov esi, pBuffer
	.if esi != NULL

		mov edx, dwVal
		mov ecx, uBits
		and byte ptr [esi][ecx], 0			; terminate string with zero
		.repeat
			shr edx, 1
			.if CARRY?
				mov byte ptr [esi][ecx-1], '1'
			.else
				mov byte ptr [esi][ecx-1], '0'
			.endif
		.untilcxz
	.endif

	ret

DwToBinStr endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                       ClearText                                                   
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

ClearText proc uses ebx uExclude:UINT

	mov ebx, 10
	.while ebx
		xor eax, eax
		push eax
		lea eax, [ebx + IDE_IOCTL]
		.if eax != uExclude
			invoke SetDlgItemText, g_hDlg, eax, esp
		.endif
		pop eax
		dec ebx
	.endw

	ret

ClearText endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                       Refresh                                                     
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
			
Refresh proc uses ebx esi edi uActiveControl:UINT

local buffer[512]:CHAR

.if uActiveControl == IDE_IOCTL

	invoke GetWindowText, g_hwndEditIoctl, addr buffer, sizeof buffer

	invoke htodw, addr buffer
	mov ebx, eax

	; Try to recognize mnemonic from value

	.if ebx != 0
		mov ecx, g_cbaMnemonics
		shr ecx, 3						; / sizeof MNEMONIC
		; ecx = number of entries in g_aszMnemonics array
		mov eax, $CTA0("")				; If mnemonic not found clear
		lea edx, g_aszMnemonics
		assume edx:ptr MNEMONIC
		.while ecx
			dec ecx			; zerobased index
			.if ebx == [edx].ioctl[ecx * sizeof MNEMONIC]
				mov eax, [edx].lpstr[ecx * sizeof MNEMONIC]
				;invoke lstrcpy, addr buffer, eax
				;lea eax, buffer
				and byte ptr [eax], 11011111y	; Lower Case to Upper Case
				.break
			.endif
		.endw
		assume edx:nothing

		invoke SetDlgItemText, g_hDlg, IDE_MNEMONIC, eax
	.endif

.elseif IDE_MNEMONIC

	; Try to recognize value from mnemonic

	xor ebx, ebx

	invoke GetDlgItemText, g_hDlg, IDE_MNEMONIC, addr buffer, sizeof buffer
	.if eax != 0

		mov esi, g_cbaMnemonics
		shr esi, 3						; / sizeof MNEMONIC
		; esi = number of entries in g_aszMnemonics array
		lea edi, g_aszMnemonics
		assume edi:ptr MNEMONIC
		.while esi
			dec esi			; zerobased index
			invoke lstrcmpi, addr buffer, [edi].lpstr[esi * sizeof MNEMONIC]
			.if eax == 0
				mov ebx, [edi].ioctl[esi * sizeof MNEMONIC]
				; Match found
				invoke wsprintf, addr buffer, $CTA0("%08X"), [edi].ioctl[esi * sizeof MNEMONIC]
				invoke SetWindowText, g_hwndEditIoctl, addr buffer
				.break
			.endif
		.endw
		assume edi:nothing

	.endif

.endif

.if ebx != 0

	; Device Type

	mov eax, ebx
	and eax, 0ffff0000h
	shr eax, 16
	mov ecx, g_cbaDeviceTypes
	shr ecx, 2						; / sizeof LPSTR
	.if eax < ecx
		mov eax, g_aszDeviceTypes[eax * sizeof LPSTR]
	.else

		.if eax == 'm'	
			mov ecx, $CTA0("MOUNTMGRCONTROLTYPE")
		.elseif eax == 'M'
			mov ecx, $CTA0("MOUNTDEVCONTROLTYPE")
		.elseif eax == 'g'
			mov ecx, $CTA0("FTCONTROLTYPE")
		.elseif eax == 'V'
			mov ecx, $CTA0("IOCTL_VOLUME_BASE")
		.elseif eax == 'A'
			mov ecx, $CTA0("FILE_DEVICE_SERVER_AVAILABILITY")
		.elseif eax == 'S'
			mov ecx, $CTA0("VOLSNAPCONTROLTYPE")
		.elseif eax == 'f'
			mov ecx, $CTA0("FTTYPE")
		.else
			xor ecx, ecx
		.endif

		.if ecx == 0
			invoke wsprintf, addr buffer, $CTA0("0x%04X"), eax		
		.else
			invoke wsprintf, addr buffer, $CTA0("0x%04X (%s)"), eax, ecx
		.endif

		lea eax, buffer

	.endif
	invoke SetDlgItemText, g_hDlg, IDE_DEVICE, eax

		
	; Function Code

	mov eax, ebx
	and eax, 011111111111100y
	shr eax, 2
	invoke wsprintf, addr buffer, addr g_szHex, eax
	invoke SetDlgItemText, g_hDlg, IDE_FUNCTION, addr buffer


	; Method
	
	mov eax, ebx	
	and eax, 011y
	invoke SetDlgItemText, g_hDlg, IDE_METHOD, g_aszMethods[eax * sizeof LPSTR]

	; Access
	
	mov eax, ebx
	and eax, 1100000000000000y
	shr eax, 14
	invoke SetDlgItemText, g_hDlg, IDE_ACCESS, g_aszAccesses[eax * sizeof LPSTR]


	; Bitfield

	invoke DwToBinStr, ebx, addr buffer, 32
	invoke SetDlgItemText, g_hDlg, IDE_BITS, addr buffer
	
.else
	invoke ClearText, uActiveControl
.endif

	ret

Refresh endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                               D I A L O G     P R O C E D U R E                                   
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

DlgProc proc uses ebx hDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

local lf:LOGFONT
local ps:PAINTSTRUCT
local bm:BITMAP
local hdc:HDC
local buffer[256]:CHAR

	mov eax, uMsg
	.if eax == WM_COMMAND

		mov eax, $LOWORD(wParam)
		.if eax == IDCANCEL
			invoke EndDialog, hDlg, 0

		.elseif eax == IDE_IOCTL
			invoke GetFocus
			.if eax == g_hwndEditIoctl
				mov eax, $HIWORD(wParam)
				.if eax == EN_CHANGE
					invoke GetWindowTextLength, g_hwndEditIoctl
					.if eax == 8
						invoke Refresh, IDE_IOCTL
					.else
						invoke ClearText, IDE_IOCTL
					.endif
				.endif
			.endif

		.elseif eax == IDE_MNEMONIC
			invoke GetFocus
			.if eax == g_hwndEditMnemonic
				mov eax, $HIWORD(wParam)
				.if eax == EN_CHANGE
					;invoke GetWindowTextLength, g_hwndEditMnemonic
					;.if eax == 8
						invoke Refresh, IDE_MNEMONIC
					;.else
					;	invoke ClearText
					;.endif
				.endif
			.endif

		.endif


	.elseif eax == WM_NOTIFY

		mov eax, lParam
		.if [NMHDR ptr [eax]].code == UDN_DELTAPOS

			invoke SendMessage, g_hwndEditIoctl, WM_GETTEXT, sizeof buffer, addr buffer
			invoke htodw, addr buffer
			mov ebx, eax

			mov eax, lParam
			mov eax, (NMHDR ptr [eax]).hwndFrom
			.if eax == g_hwndSpinFunction
		
				mov eax, ebx
				and eax, 011111111111100y	; Extract function code
				shr eax, 2

				mov ecx, lParam
				mov ecx, (NM_UPDOWN ptr [ecx]).iDelta

				add eax, ecx
				and eax, 0111111111111y		; Mask function code
				shl eax, 2

				and ebx, not 011111111111100y
				or ebx, eax

			.elseif eax == g_hwndSpinMethod

				mov eax, ebx
				and eax, 011y				; Extract method

				mov ecx, lParam
				mov ecx, (NM_UPDOWN ptr [ecx]).iDelta

				add eax, ecx
				and eax, 011y

				and ebx, not 011y			; Mask method
				or ebx, eax

			.elseif eax == g_hwndSpinAccess

				mov eax, ebx
				and eax, 01100000000000000y	; Extract access
				shr eax, 14

				mov ecx, lParam
				mov ecx, (NM_UPDOWN ptr [ecx]).iDelta

				add eax, ecx
				and eax, 011y
				shl eax, 14

				and ebx, not 01100000000000000y	; Mask access
				or ebx, eax

			.endif

			invoke wsprintf, addr buffer, $CTA0("%08X"), ebx
			invoke SendMessage, g_hwndEditIoctl, WM_SETTEXT, 0, addr buffer

			invoke Refresh, IDE_IOCTL

		.endif


	.elseif eax == WM_INITDIALOG

		mrm g_hDlg, hDlg

		invoke SetWindowText, hDlg, $CTA0("I/O Control Code Decoder")

		; Set Dialog Icon

		invoke LoadIcon, g_hInstance, IDI_ICON
		invoke SendMessage, hDlg, WM_SETICON, ICON_BIG, eax


		; Set static font

		mov g_hwndStaticMnemonics, $invoke(GetDlgItem, hDlg, IDC_RECOGNIZES_XXX_MNEMONICS)

		mov	g_hFontOld1, $invoke(SendMessage, g_hwndStaticMnemonics, WM_GETFONT, 0, 0)
		invoke GetObject, g_hFontOld1, sizeof LOGFONT, addr lf

		or lf.lfWeight, FW_BOLD
		invoke CreateFontIndirect, addr lf		
		mov	g_hFontBold, eax

		invoke SendMessage, g_hwndStaticMnemonics, WM_SETFONT, g_hFontBold, FALSE

		mov eax, g_cbaMnemonics
		xor edx, edx
		mov ecx, sizeof MNEMONIC
		div ecx
		
		invoke wsprintf, addr buffer, $CTA0("Recognizes %d mnemonics"), eax

		invoke SetWindowText, g_hwndStaticMnemonics, addr buffer

	


		mov g_hwndEditIoctl, $invoke(GetDlgItem, hDlg, IDE_IOCTL)
		mov g_hwndEditMnemonic, $invoke(GetDlgItem, hDlg, IDE_MNEMONIC)

		; Thnx to James Brown for idea

		invoke MaskEditControl, g_hwndEditIoctl, $CTA0("0123456789abcdefABCDEF"), TRUE
		invoke SendMessage, g_hwndEditIoctl, EM_LIMITTEXT, 8, 0

		; Init with zero

		invoke SendMessage, g_hwndEditIoctl, WM_SETTEXT, 0, $CTA0("0")

		invoke CreateUpDownControl, WS_CHILD + WS_BORDER + WS_VISIBLE + UDS_ALIGNRIGHT, \
							375, 107, 20, 20, hDlg, 0, g_hInstance, NULL, 0FFFh, 0, 0
		mov g_hwndSpinFunction, eax

		invoke CreateUpDownControl, WS_CHILD + WS_BORDER + WS_VISIBLE + UDS_ALIGNRIGHT, \
							375, 136, 20, 20, hDlg, 0, g_hInstance, NULL, 3, 0, 0
		mov g_hwndSpinMethod, eax

		invoke CreateUpDownControl, WS_CHILD + WS_BORDER + WS_VISIBLE + UDS_ALIGNRIGHT, \
							375, 165, 20, 20, hDlg, 0, g_hInstance, NULL, 3, 0, 0
		mov g_hwndSpinAccess, eax



		mov g_hbmp, $invoke(LoadBitmap, g_hInstance, IDI_BMP)

		; Get size of bmp

		invoke GetObject, g_hbmp, sizeof BITMAP, addr bm
		push bm.bmWidth
		pop g_BmpDimension.Siz.x
		push bm.bmHeight
		pop g_BmpDimension.Siz.y

		mov hdc, $invoke(GetDC, hDlg)
		mov g_hMemDC, $invoke(CreateCompatibleDC, eax)
		invoke ReleaseDC, hDlg, hdc



		; Create and set font for bitfield

		mov g_hFontOld2, $invoke(SendDlgItemMessage, hDlg, IDE_BITS, WM_GETFONT, 0, 0)
		invoke GetObject, g_hFontOld2, sizeof LOGFONT, addr lf

		lea ecx, lf.lfFaceName
		invoke lstrcpy, ecx, $CTA0("Courier New")
		invoke CreateFontIndirect, addr lf		
		mov	g_hFontCourier, eax

		invoke SendDlgItemMessage, hDlg, IDE_BITS, WM_SETFONT, g_hFontCourier, FALSE



		; Expose some example

		invoke SendMessage, g_hwndEditIoctl, WM_SETTEXT, 0, $CTA0("000B0000")
		invoke Refresh, IDE_IOCTL

		;invoke SetDlgItemText, g_hDlg, IDE_BITS, $CTA0("10101010101010101010101010101010")
		;invoke SetDlgItemText, g_hDlg, IDE_MNEMONIC, $CTA0("IOCTL_INTERNAL_UNREGISTER_FOR_REMOVAL_RELATIONS")


		; Add about menu
		push ebx
		invoke GetSystemMenu, hDlg, FALSE
		mov ebx, eax
		invoke InsertMenu, ebx, -1, MF_BYPOSITION + MF_SEPARATOR, 0, 0
		invoke InsertMenu, ebx, -1, MF_BYPOSITION + MF_STRING, IDM_ABOUT, offset szAbout
		pop ebx



    .elseif eax == WM_CTLCOLORSTATIC
		mov	eax, lParam
		.if eax == g_hwndStaticMnemonics

			invoke SetTextColor, wParam, $invoke(GetSysColor, COLOR_3DSHADOW)

		.endif

		invoke SetBkMode, wParam, TRANSPARENT
		invoke GetSysColorBrush, COLOR_3DFACE
		ret



    .elseif eax == WM_PAINT
		mov	hdc, $invoke(BeginPaint, hDlg, addr ps)
		invoke DrawTransparent, hdc, g_hMemDC, g_hbmp, addr g_BmpDimension
		invoke EndPaint, hDlg, addr ps



	.elseif eax == WM_DESTROY

		;invoke SendMessage, g_hwndBits, WM_SETFONT, g_hFontOld, FALSE
		invoke DeleteObject, g_hMemDC
		invoke DeleteObject, g_hbmp

		invoke SendMessage, g_hwndStaticMnemonics, WM_SETFONT, g_hFontOld1, FALSE
		invoke DeleteObject, g_hFontBold

		invoke SendDlgItemMessage, hDlg, IDE_BITS, WM_SETFONT, g_hFontOld2, FALSE
		invoke DeleteObject, g_hFontCourier		

	.elseif eax == WM_SYSCOMMAND
		.if wParam == IDM_ABOUT
			invoke MessageBox, hDlg, addr szWrittenBy, addr szAbout, MB_ICONINFORMATION
		.endif
 		xor eax, eax
 		ret
 
	.else

		xor eax, eax
		ret
	
	.endif

	xor eax, eax
	inc eax
	ret
    
DlgProc endp

IFDEF DEBUG

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                       PrintConsole                                                
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

PrintConsole proc psz:LPSTR, dwAttributes:DWORD

local csbi:CONSOLE_SCREEN_BUFFER_INFO
local cb:DWORD

	.if dwAttributes != 0
		invoke GetConsoleScreenBufferInfo, g_hConsoleOutput, addr csbi
		invoke SetConsoleTextAttribute, g_hConsoleOutput, dwAttributes
	.endif

	.if psz != NULL
		invoke lstrlen, psz
		.if eax
			mov ecx, eax
			invoke WriteFile, g_hConsoleOutput, psz, ecx, addr cb, NULL
		.endif
	.endif

	.if dwAttributes != 0
		movzx eax, csbi.wAttributes
		invoke SetConsoleTextAttribute, g_hConsoleOutput, eax
	.endif

	ret

PrintConsole endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                        CheckDuplicates                                            
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

CheckDuplicates proc uses esi edi ebx

local buffer[256]:CHAR 
local CodeInQuestion:DWORD
local cch:UINT
local fBad:BOOL

	and fBad, FALSE

	invoke AllocConsole
	.if eax != FALSE

		invoke GetStdHandle, STD_INPUT_HANDLE
		mov g_hConsoleInput, eax

		invoke GetStdHandle, STD_OUTPUT_HANDLE
		mov g_hConsoleOutput, eax

		.if ( g_hConsoleInput != INVALID_HANDLE_VALUE ) && ( g_hConsoleOutput != INVALID_HANDLE_VALUE )

			;:::::::::::::::::::
			; Check values first
			;:::::::::::::::::::

			mov ebx, g_cbaMnemonics
			shr ebx, 3						; / sizeof MNEMONIC
			; ecx = number of entries in g_aszMnemonics array

			lea edi, g_aszMnemonics
			assume edi:ptr MNEMONIC
			.while ebx
				dec ebx			; zerobased index


				mov eax, [edi].ioctl[ebx * sizeof MNEMONIC]
				mov CodeInQuestion, eax

				mov esi, g_cbaMnemonics
				shr esi, 3						; / sizeof MNEMONIC
				; ecx = number of entries in g_aszMnemonics array

				.while esi
					dec esi			; zerobased index
					mov eax, [edi].ioctl[esi * sizeof MNEMONIC]
					.if ( eax == CodeInQuestion ) && ( esi != ebx )

						mov fBad, TRUE				; set bad flag

						invoke wsprintf, addr buffer, $CTA0("\n%03d:  %08X  "), ebx, [edi].ioctl[ebx * sizeof MNEMONIC]
						invoke PrintConsole, addr buffer, 0

						invoke PrintConsole, [edi].lpstr[ebx * sizeof MNEMONIC], 0
						invoke PrintConsole, $CTA0("\n"), 0


						invoke wsprintf, addr buffer, $CTA0("%03d:  %08X  "), esi, [edi].ioctl[esi * sizeof MNEMONIC]
						invoke PrintConsole, addr buffer, 0

						invoke PrintConsole, [edi].lpstr[esi * sizeof MNEMONIC], 0
						invoke PrintConsole, $CTA0("\n"), 0
				
					.endif
				.endw

			.endw
			assume edi:nothing






			.if fBad
				invoke PrintConsole, $CTA0("\nPress any key to continue..."), 0
				invoke ReadConsole, g_hConsoleInput, addr buffer, 5, addr cch, 0
			.endif

			invoke FreeConsole

		.else
			invoke MessageBox, NULL, $CTA0("Couldn't get console handles"), NULL, MB_OK
		.endif
	.else
		invoke MessageBox, NULL, $CTA0("Couldn't allocate console"), NULL, MB_OK
	.endif

	ret

CheckDuplicates endp

ENDIF	; DEBUG

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                           start                                                   
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

start:

IFDEF DEBUG
	invoke CheckDuplicates
ENDIF

	mov g_hInstance, $invoke(GetModuleHandle, NULL)
	invoke DialogBoxParam, g_hInstance, IDD_MAIN, NULL, addr DlgProc, 0

	invoke ExitProcess, 0

end start

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                                                   
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:make

set exe=IoctlDecoder

:makerc
if exist rsrc.obj goto final
	\masm32\bin\rc /v rsrc.rc
	\masm32\bin\cvtres /machine:ix86 rsrc.res
	if errorlevel 0 goto final
		echo.
		pause
		exit

:final

rem Use DEBUG or RELEASE to make appropriate build
set conf=RELEASE

if exist rsrc.res del rsrc.res

\masm32\bin\ml /nologo /c /coff ioctls.asm
	
\masm32\bin\ml /nologo /c /coff /D%conf% %exe%.bat
\masm32\bin\link /nologo /subsystem:windows /merge:POINTERS=.rdata %exe%.obj ioctls.obj rsrc.obj

del %exe%.obj

echo.
pause
