Sulaiman Chang Personal Website
Tutorial 31 : Listview Control

tut_31a.asm
format PE GUI 4.0
entry start

M_MAIN		= 10000
MI_ICON		= 0x0000
MI_SMALLICON	= 0x0002
MI_LIST		= 0x0003
MI_REPORT	= 0x0001

include '%fasminc%\win32a.inc'

macro RGB cR, cG, cB {
	xor	eax,eax	;clear the eax
	mov	ah,cB
	shl	eax,8
	mov	ah,cG
	mov	al,cR
}

section '.data' data readable writeable
	wndH		dd ?
	insH		dd ?
	wndClsName	db 'TUT_31',0
	wndTitle	db 'Tutorial 31',0

	wndCls	WNDCLASS
	wndMsg	MSG

	ctlClsNameLv	db 'SysListView32',0

	lvH		dd ?
	lvTxt1		db 'File Name',0
	lvTxt2		db 'Size',0
	lvTxt3		db '%lu',0
	lvSortSize	dd 0
	lvSortFile	dd 0

	menuH		dd ?

	lvI1a	db 'Durian',0
	lvI1b	db '34',0
	lvI2a	db 'Banana',0
	lvI2b	db '54',0
	lvI3a	db 'Watermelon',0
	lvI3b	db '44',0
	lvI4a	db 'Apple',0
	lvI4b	db '55',0
	lvI5a	db 'Papaya',0
	lvI5b	db '1',0

section '.code' code readable executable
start:
	invoke	GetModuleHandle,0
		mov  [insH],eax
		mov  [wndCls.hInstance],eax
		mov  [wndCls.style],CS_HREDRAW or CS_VREDRAW
		mov  [wndCls.lpfnWndProc],window_procedure
		mov  [wndCls.lpszClassName],wndClsName
		mov  [wndCls.lpszMenuName],10000
		mov  [wndCls.hbrBackground],COLOR_BTNFACE+1
	invoke	LoadIcon,NULL,IDI_APPLICATION
		mov  [wndCls.hIcon],eax
	invoke	LoadCursor,NULL,IDC_ARROW
		mov  [wndCls.hCursor],eax
	invoke	RegisterClass,wndCls

	invoke	CreateWindowEx,WS_EX_CLIENTEDGE,\
		wndClsName,wndTitle,\
		WS_OVERLAPPEDWINDOW + WS_VISIBLE,\
		CW_USEDEFAULT,CW_USEDEFAULT,400,240,\
		NULL,NULL,[insH],NULL
		mov  [wndH],eax

	invoke	InitCommonControls

;+---------------------------+
;| entering the message loop |
;+---------------------------+
window_message_loop_start:
	invoke	GetMessage,wndMsg,NULL,0,0
		or    eax,eax
		je    window_message_loop_end
	invoke	TranslateMessage,wndMsg
	invoke	DispatchMessage,wndMsg
		jmp	window_message_loop_start

window_message_loop_end:
	invoke	ExitProcess,0

;+----------------------+
;| the window procedure |
;+----------------------+
proc window_procedure,hWnd,uMsg,wParam,lParam
		push ebx esi edi
		cmp  [uMsg],WM_NOTIFY
		je   wmNOTIFY
		cmp  [uMsg],WM_CREATE
		je   wmCREATE
		cmp  [uMsg],WM_SIZE
		je   wmSIZE
		cmp  [uMsg],WM_DESTROY
		je   wmDESTROY

	wmDEFAULT:
		invoke	DefWindowProc,[hWnd],[uMsg],[wParam],[lParam]
			jmp  wmBYE

	wmNOTIFY:
			mov  ebx,[lParam]
			mov  eax,[ebx + NMHDR.hwndFrom]
			cmp  eax,[lvH]
			jne  wmDEFAULT

			cmp  [ebx + NMHDR.code],LVN_COLUMNCLICK
			je   wmNOTIFY_LVN_COLUMNCLICK
			cmp  [ebx + NMHDR.code],NM_DBLCLK
			je   wmNOTIFY_NM_DBLCLK
			jmp  wmDEFAULT

		wmNOTIFY_LVN_COLUMNCLICK:
			cmp  [ebx + NMLISTVIEW.iSubItem],1
			je   COLUMNCLICK_SIZE
			jmp  COLUMNCLICK_FILE

			COLUMNCLICK_SIZE:
					cmp  [lvSortSize],1
					je   SIZE_1

				SIZE_0:
					mov  [lvSortSize],1
					jmp  @f

				SIZE_1:
					mov  [lvSortSize],2

			@@:
				invoke	SendMessage,[lvH],LVM_SORTITEMS,[lvSortSize],lv_compare
				call	lv_param_update
					jmp  wmBYE

			COLUMNCLICK_FILE:
					cmp  [lvSortFile],3
					je   FILE_4

				FILE_3:
					mov  [lvSortFile],3
					jmp  @f

				FILE_4:
					mov  [lvSortFile],4
			@@:
				invoke	SendMessage,[lvH],LVM_SORTITEMS,[lvSortFile],lv_compare
				call	lv_param_update
					jmp  wmBYE
			
		wmNOTIFY_NM_DBLCLK:
			invoke	MessageBox,NULL,wndClsName,wndClsName,MB_OK
				jmp  wmBYE			

	
	wmSIZE:
			mov  eax,[lParam]
			mov  edx,eax
			and  eax,0xFFFF
			shr  edx,16
		invoke	MoveWindow,[lvH],0,0,eax,edx,TRUE
			jmp  wmBYE

	wmCREATE:
		invoke	CreateWindowEx,NULL,ctlClsNameLv,NULL,\
			LVS_REPORT + WS_CHILD + WS_VISIBLE,\
			0,0,0,0,\
			[hWnd],NULL,[insH],NULL
			mov  [lvH],eax
		call	lv_col_insert
		call	lv_col_info_fill
		invoke	GetMenu,[hWnd]
			mov  [menuH],eax
		invoke	CheckMenuRadioItem,eax,MI_ICON,MI_REPORT,MI_REPORT,MF_CHECKED
			jmp  wmBYE

	wmDESTROY:
		invoke	PostQuitMessage,0

	wmBYE:
		pop edi esi ebx
		return
   endp

proc lv_param_update
	lvi1	LVITEM
	enter
		invoke	SendMessage,[lvH],LVM_GETITEMCOUNT,0,0
			mov  ebx,eax
			mov  [lvi1.mask],LVIF_PARAM
			mov  [lvi1.iSubItem],0
			mov  [lvi1.iItem],0
	@@:
			cmp  ebx,0
			je   @f
			push [lvi1.iItem]
			pop  [lvi1.lParam]
			lea  eax,[lvi1]
		invoke	SendMessage,[lvH],LVM_SETITEM,0,eax
			inc  [lvi1.iItem]
			dec  ebx
			jmp  @b
	@@:
		return
endp

proc convert_strhval,str
	result	dd ?
	enter
		push ecx edi edx esi
		mov  [result],0
		mov  edi,[str]
	invoke	lstrlen,[str]

	a:
		cmp  eax,0
		je   b
		xor  edx,edx
		mov  dl,[edi]
		sub  dl,'0'
		mov  esi,eax
		dec  esi
		push eax
		mov  eax,edx
		push ebx
		mov  ebx,10
	@@:
		cmp  esi,0
		je   @f
		mul  ebx
		dec  esi
		jmp  @b
	@@:
		pop  ebx
		add  [result],eax
		pop  eax
		inc  edi
		dec  eax
		jmp  a
	b:
		pop  esi edx edi ecx
		mov  eax,[result]
		return
endp

proc lv_compare,lParam1,lParam2,lParamSort
	buf1	rb 0xFF
	buf2	rb 0xFF
	lvi0	LVITEM
	enter
		mov  [lvi0.mask],LVIF_TEXT
		lea  eax,[buf1]
		mov  [lvi0.pszText],eax
		mov  [lvi0.cchTextMax],0xFF

		cmp  [lParamSort],2
		jbe  compare_1
		jmp  compare_3
		return

	compare_1:
			push edi
			mov  [lvi0.iSubItem],1
			lea  eax,[lvi0]
		invoke	SendMessage,[lvH],LVM_GETITEMTEXT,[lParam1],eax
			lea  eax,[buf1]
		stdcall	convert_strhval,eax
			mov  edi,eax
			lea  eax,[lvi0]
		invoke	SendMessage,[lvH],LVM_GETITEMTEXT,[lParam2],eax
			lea  eax,[buf1]
		stdcall	convert_strhval,eax
			cmp  [lParamSort],1
			jne  @f
			sub  edi,eax
			mov  eax,edi
			jmp  compare_1_exit
		@@:
			sub  eax,edi

		compare_1_exit:
				pop  edi
				return

	compare_3:
			mov  [lvi0.iSubItem],0
			lea  eax,[lvi0]
		invoke	SendMessage,[lvH],LVM_GETITEMTEXT,[lParam1],eax
			lea  edx,[buf2]		;destination
			lea  eax,[buf1]		;source
		invoke	lstrcpy,edx,eax
			lea  eax,[lvi0]
		invoke	SendMessage,[lvH],LVM_GETITEMTEXT,[lParam2],eax
			lea  edx,[buf2]
			lea  eax,[buf1]
			cmp  [lParamSort],3
			jne  @f
		invoke	lstrcmpi,edx,eax
			return
		@@:
		invoke	lstrcmpi,eax,edx
			return

endp

proc lv_col_insert
	lvCol	LVCOLUMN
	enter
		mov  [lvCol.mask],LVCF_TEXT + LVCF_WIDTH
		mov  [lvCol.pszText],lvTxt1
		mov  [lvCol.cx],150
		lea  edx,[lvCol]
		push edx
	invoke	SendMessage,[lvH],LVM_INSERTCOLUMN,0,edx
		mov  [lvCol.pszText],lvTxt2
		mov  [lvCol.cx],100
	invoke	SendMessage,[lvH],LVM_INSERTCOLUMN,1
		return
endp

proc lv_col_info_fill
	lvItem	LVITEM
	enter
		push lvI5b
		push lvI5a
		push lvI4b
		push lvI4a
		push lvI3b
		push lvI3a
		push lvI2b
		push lvI2a
		push lvI1b
		push lvI1a
		mov  ebx,0
		
	@@:
		mov  [lvItem.mask],LVIF_TEXT + LVIF_PARAM
		pop  [lvItem.pszText]
		mov  [lvItem.iSubItem],0
		mov  [lvItem.iItem],ebx
		mov  [lvItem.lParam],ebx
		lea  eax,[lvItem]
	invoke	SendMessage,[lvH],LVM_INSERTITEM,0,eax
		mov  [lvItem.mask],LVIF_TEXT
		inc  [lvItem.iSubItem]
		pop  [lvItem.pszText]
		lea  eax,[lvItem]
	invoke	SendMessage,[lvH],LVM_SETITEM,0,eax
		inc  ebx
		cmp  ebx,5
		jb   @b
		return
endp

section '.idata' import data readable
	library	kernel32, 'KERNEL32.DLL',\
		user32,   'USER32.DLL',\
		comctl32, 'COMCTL32.DLL'

	include '%fasminc%\apia\Kernel32.inc'
	include '%fasminc%\apia\User32.inc'
	include '%fasminc%\apia\Comctl32.inc'

section '.rsrc' resource from 'tut_31.rc.res'
Result : tut_31a.asm



tut_31b.asm
format PE GUI 4.0
entry start

M_MAIN		= 10000
MI_ICON		= 0x0000
MI_SMALLICON	= 0x0002
MI_LIST		= 0x0003
MI_REPORT	= 0x0001

include '%fasminc%\win32a.inc'

macro RGB cR, cG, cB {
	xor	eax,eax	;clear the eax
	mov	ah,cB
	shl	eax,8
	mov	ah,cG
	mov	al,cR
}

struct WIN32_FIND_DATA
	.dwFileAttributes	dd ?
	.ftCreationTime		dq ?
	.ftLastAccessTime	dq ?
	.ftLastWriteTime	dq ?
	.nFileSizeHigh		dd ?
	.nFileSizeLow		dd ?
	.dwReserved0		dd ?
	.dwReserved1		dd ?
	.cFileName		rb 260
	.cAlternateFileName	rb 14
ends

section '.data' data readable writeable
	wndH		dd ?
	insH		dd ?
	wndClsName	db 'TUT_31',0
	wndTitle	db 'Tutorial 31',0

	wndCls	WNDCLASS
	wndMsg	MSG

	ctlClsNameLv	db 'SysListView32',0

	lvH		dd ?
	lvTxt1		db 'File Name',0
	lvTxt2		db 'Size',0
	lvTxt3		db '%lu',0
	lvSortSize	dd 0
	lvSortFile	dd 0

	menuH		dd ?

	fFileH		dd ?
	fData		WIN32_FIND_DATA
	fTxt1		db '*.*',0


section '.code' code readable executable
start:
	invoke	GetModuleHandle,0
		mov  [insH],eax
		mov  [wndCls.hInstance],eax
		mov  [wndCls.style],CS_HREDRAW or CS_VREDRAW
		mov  [wndCls.lpfnWndProc],window_procedure
		mov  [wndCls.lpszClassName],wndClsName
		mov  [wndCls.lpszMenuName],10000
		mov  [wndCls.hbrBackground],COLOR_BTNFACE+1
	invoke	LoadIcon,NULL,IDI_APPLICATION
		mov  [wndCls.hIcon],eax
	invoke	LoadCursor,NULL,IDC_ARROW
		mov  [wndCls.hCursor],eax
	invoke	RegisterClass,wndCls

	invoke	CreateWindowEx,WS_EX_CLIENTEDGE,\
		wndClsName,wndTitle,\
		WS_OVERLAPPEDWINDOW + WS_VISIBLE,\
		CW_USEDEFAULT,CW_USEDEFAULT,400,240,\
		NULL,NULL,[insH],NULL
		mov  [wndH],eax

	invoke	InitCommonControls

;+---------------------------+
;| entering the message loop |
;+---------------------------+
window_message_loop_start:
	invoke	GetMessage,wndMsg,NULL,0,0
		or    eax,eax
		je    window_message_loop_end
	invoke	TranslateMessage,wndMsg
	invoke	DispatchMessage,wndMsg
		jmp	window_message_loop_start

window_message_loop_end:
	invoke	ExitProcess,0

;+----------------------+
;| the window procedure |
;+----------------------+
proc window_procedure,hWnd,uMsg,wParam,lParam
		push ebx esi edi
		cmp  [uMsg],WM_COMMAND
		je   wmCOMMAND
		cmp  [uMsg],WM_NOTIFY
		je   wmNOTIFY
		cmp  [uMsg],WM_CREATE
		je   wmCREATE
		cmp  [uMsg],WM_SIZE
		je   wmSIZE
		cmp  [uMsg],WM_DESTROY
		je   wmDESTROY

	wmDEFAULT:
		invoke	DefWindowProc,[hWnd],[uMsg],[wParam],[lParam]
			jmp  wmBYE

	wmCOMMAND:
			cmp  [lParam],0
			jne  wmBYE
		invoke	GetWindowLong,[lvH],GWL_STYLE
			and  eax,not LVS_TYPEMASK
			mov  edx,[wParam]
			and  edx,0xFFFF
			push edx
			or   eax,edx
		invoke	SetWindowLong,[lvH],GWL_STYLE,eax
			pop  edx
		invoke	CheckMenuRadioItem,[menuH],MI_ICON,MI_LIST,edx,MF_CHECKED
			jmp  wmBYE

	wmNOTIFY:
			mov  ebx,[lParam]
			mov  eax,[ebx + NMHDR.hwndFrom]
			cmp  eax,[lvH]
			jne  wmDEFAULT

			cmp  [ebx + NMHDR.code],LVN_COLUMNCLICK
			je   wmNOTIFY_LVN_COLUMNCLICK
			cmp  [ebx + NMHDR.code],NM_DBLCLK
			je   wmNOTIFY_NM_DBLCLK
			jmp  wmDEFAULT

		wmNOTIFY_LVN_COLUMNCLICK:
			cmp  [ebx + NMLISTVIEW.iSubItem],1
			je   COLUMNCLICK_SIZE
			jmp  COLUMNCLICK_FILE

			COLUMNCLICK_SIZE:
					cmp  [lvSortSize],1
					je   SIZE_1

				SIZE_0:
					mov  [lvSortSize],1
					jmp  @f

				SIZE_1:
					mov  [lvSortSize],2

			@@:
				invoke	SendMessage,[lvH],LVM_SORTITEMS,[lvSortSize],lv_compare
				call	lv_param_update
					jmp  wmBYE

			COLUMNCLICK_FILE:
					cmp  [lvSortFile],3
					je   FILE_4

				FILE_3:
					mov  [lvSortFile],3
					jmp  @f

				FILE_4:
					mov  [lvSortFile],4
			@@:
				invoke	SendMessage,[lvH],LVM_SORTITEMS,[lvSortFile],lv_compare
				call	lv_param_update
					jmp  wmBYE
			
		wmNOTIFY_NM_DBLCLK:
			call	lv_item_focus
				jmp  wmBYE			

	
	wmSIZE:
			mov  eax,[lParam]
			mov  edx,eax
			and  eax,0xFFFF
			shr  edx,16
		invoke	MoveWindow,[lvH],0,0,eax,edx,TRUE
			jmp  wmBYE

	wmCREATE:
		invoke	CreateWindowEx,NULL,ctlClsNameLv,NULL,\
			LVS_REPORT + WS_CHILD + WS_VISIBLE,\
			0,0,0,0,\
			[hWnd],NULL,[insH],NULL
			mov  [lvH],eax
		call	lv_col_insert
		call	lv_col_info_fill
			RGB 0xAF,0xB5,0xC9
		invoke	SendMessage,[lvH],LVM_SETTEXTCOLOR,0,eax
			RGB 0x2E,0x35,0x50
		invoke	SendMessage,[lvH],LVM_SETBKCOLOR,0,eax
			RGB 0x2E,0x35,0x50
		invoke	SendMessage,[lvH],LVM_SETTEXTBKCOLOR,0,eax
		invoke	GetMenu,[hWnd]
			mov  [menuH],eax
		invoke	CheckMenuRadioItem,eax,MI_ICON,MI_LIST,MI_REPORT,MF_CHECKED
			jmp  wmBYE

	wmDESTROY:
		invoke	PostQuitMessage,0

	wmBYE:
		pop edi esi ebx
		return
   endp

proc lv_item_focus
	lvi4	LVITEM
	buf4	rb 0xFF
	enter

	invoke	SendMessage,[lvH],LVM_GETNEXTITEM,-1,LVNI_FOCUSED
		mov  [lvi4.iItem],eax
		mov  [lvi4.iSubItem],0
		mov  [lvi4.mask],LVIF_TEXT
		lea  eax,[buf4]
		mov  [lvi4.pszText],eax
		mov  [lvi4.cchTextMax],0xFF
		lea  eax,[lvi4]
	invoke	SendMessage,[lvH],LVM_GETITEM,0,eax
		lea  eax,[buf4]
	invoke	MessageBox,NULL,eax,wndTitle,MB_OK
	return
endp

proc lv_param_update
	lvi1	LVITEM
	enter
		invoke	SendMessage,[lvH],LVM_GETITEMCOUNT,0,0
			mov  ebx,eax
			mov  [lvi1.mask],LVIF_PARAM
			mov  [lvi1.iSubItem],0
			mov  [lvi1.iItem],0
	@@:
			cmp  ebx,0
			je   @f
			push [lvi1.iItem]
			pop  [lvi1.lParam]
			lea  eax,[lvi1]
		invoke	SendMessage,[lvH],LVM_SETITEM,0,eax
			inc  [lvi1.iItem]
			dec  ebx
			jmp  @b
	@@:
		return
endp

proc convert_strhval,str
	result	dd ?
	enter
		push ecx edi edx esi
		mov  [result],0
		mov  edi,[str]
	invoke	lstrlen,[str]

	a:
		cmp  eax,0
		je   b
		xor  edx,edx
		mov  dl,[edi]
		sub  dl,'0'
		mov  esi,eax
		dec  esi
		push eax
		mov  eax,edx
		push ebx
		mov  ebx,10
	@@:
		cmp  esi,0
		je   @f
		mul  ebx
		dec  esi
		jmp  @b
	@@:
		pop  ebx
		add  [result],eax
		pop  eax
		inc  edi
		dec  eax
		jmp  a
	b:
		pop  esi edx edi ecx
		mov  eax,[result]
		return
endp

proc lv_compare,lParam1,lParam2,lParamSort
	buf1	rb 0xFF
	buf2	rb 0xFF
	lvi0	LVITEM
	enter
		mov  [lvi0.mask],LVIF_TEXT
		lea  eax,[buf1]
		mov  [lvi0.pszText],eax
		mov  [lvi0.cchTextMax],0xFF

		cmp  [lParamSort],2
		jbe  compare_1
		jmp  compare_3
		return

	compare_1:
			push edi
			mov  [lvi0.iSubItem],1
			lea  eax,[lvi0]
		invoke	SendMessage,[lvH],LVM_GETITEMTEXT,[lParam1],eax
			lea  eax,[buf1]
		stdcall	convert_strhval,eax
			mov  edi,eax
			lea  eax,[lvi0]
		invoke	SendMessage,[lvH],LVM_GETITEMTEXT,[lParam2],eax
			lea  eax,[buf1]
		stdcall	convert_strhval,eax
			cmp  [lParamSort],1
			jne  @f
			sub  edi,eax
			mov  eax,edi
			jmp  compare_1_exit
		@@:
			sub  eax,edi

		compare_1_exit:
				pop  edi
				return

	compare_3:
			mov  [lvi0.iSubItem],0
			lea  eax,[lvi0]
		invoke	SendMessage,[lvH],LVM_GETITEMTEXT,[lParam1],eax
			lea  edx,[buf2]		;destination
			lea  eax,[buf1]		;source
		invoke	lstrcpy,edx,eax
			lea  eax,[lvi0]
		invoke	SendMessage,[lvH],LVM_GETITEMTEXT,[lParam2],eax
			lea  edx,[buf2]
			lea  eax,[buf1]
			cmp  [lParamSort],3
			jne  @f
		invoke	lstrcmpi,edx,eax
			return
		@@:
		invoke	lstrcmpi,eax,edx
			return

endp

proc lv_col_insert
	lvCol	LVCOLUMN
	enter
		mov  [lvCol.mask],LVCF_TEXT + LVCF_WIDTH
		mov  [lvCol.pszText],lvTxt1
		mov  [lvCol.cx],150
		lea  edx,[lvCol]
		push edx
	invoke	SendMessage,[lvH],LVM_INSERTCOLUMN,0,edx
		or   [lvCol.mask],LVCF_FMT
		mov  [lvCol.fmt],LVCFMT_RIGHT
		mov  [lvCol.pszText],lvTxt2
		mov  [lvCol.cx],100
	invoke	SendMessage,[lvH],LVM_INSERTCOLUMN,1
		return
endp

proc lv_col_info_fill
		push edi
	invoke	FindFirstFile,fTxt1,fData
		cmp  eax,INVALID_HANDLE_VALUE
		je   fill_exit
		mov  [fFileH],eax
		xor  edi,edi
		
	fill_start:
			cmp  eax,0
			je   fill_end

			cmp  [fData.dwFileAttributes],FILE_ATTRIBUTE_DIRECTORY
			je   @f
		stdcall	lv_col_info_insert,edi
			inc  edi

		@@:
		invoke	FindNextFile,[fFileH],fData
			jmp  fill_start

	fill_end:
		invoke	FindClose,[fFileH]
		
	fill_exit:
		pop  edi
		return
endp

proc lv_col_info_insert,row
	lvi2	LVITEM
	buf3	rb 20
	enter

		mov  [lvi2.mask],LVIF_TEXT + LVIF_PARAM
		mov  [lvi2.pszText],fData.cFileName
		mov  [lvi2.iSubItem],0
		push [row]
		push [row]
		pop  [lvi2.iItem]
		pop  [lvi2.lParam]

		lea  eax,[lvi2]
	invoke	SendMessage,[lvH],LVM_INSERTITEM,0,eax
		mov  [lvi2.mask],LVIF_TEXT
		inc  [lvi2.iSubItem]
		lea  eax,[buf3]
	invoke	wsprintf,eax,lvTxt3,[fData.nFileSizeLow]
		lea  eax,[buf3]
		mov  [lvi2.pszText],eax
		lea  eax,[lvi2]
	invoke	SendMessage,[lvH],LVM_SETITEM,0,eax
		return
endp

section '.idata' import data readable
	library	kernel32, 'KERNEL32.DLL',\
		user32,   'USER32.DLL',\
		comctl32, 'COMCTL32.DLL'

	include '%fasminc%\apia\Kernel32.inc'
	include '%fasminc%\apia\User32.inc'
	include '%fasminc%\apia\Comctl32.inc'

section '.rsrc' resource from 'tut_31.rc.res'


tut_31.res
#define M_MAIN		10000
#define MI_ICON		0x0000
#define MI_SMALLICON	0x0002
#define MI_LIST		0x0003
#define MI_REPORT	0x0001

M_MAIN MENU
{
	POPUP "&View"
	{
		MENUITEM "Lar&ge Icons",MI_ICON
		MENUITEM "S&mall Icons",MI_SMALLICON
		MENUITEM "&List",MI_LIST
		MENUITEM "&Details",MI_REPORT
	}
}

Result : tut_31b.asm

Copyright © 2004 Sulaiman Chang. All Rights Reserved.