Assembly Language Programming

June 21, 2012

FASM – Win32 Property Sheets Example

Filed under: Assembly Language — Tags: , , — programmer209 @ 12:43 pm

In this post I use FASM (the Flat Assembler) to implement Win32 Property Sheets in x86 assembly language.

Related Posts

FASM – Win32 Dialog Boxes

FASM – Win32 Hello World

Example One

The first example provides a template for implementing property sheets in FASM. It does nothing except create a property sheet with two blank property pages.

Only a few simple steps are required to set up a property sheet. First for each page in the sheet, a PROPSHEETPAGE structure is filled in. Then a PROPSHEETHEADER structure is filled in for the overall property sheet. Finally the Win32 PropertySheet function is called, taking one argument – the address of the PROPSHEETHEADER.

The PROPSHEETHEADER and PROPSHEETPAGE structures are created in the ‘.data’ section of the code. All of the members of these structures are initialised to either 0 or NULL, depending on whether they are integer values or pointers.

The example includes a callback function for the property sheet, called PropSheetProc. This function is called when the sheet is first created and initialised. It handles the PSCB_PRECREATE and PSCB_INITIALIZED messages. The callback function is user defined and is only needed if the user wants customised handling of these 2 messages. The function always returns 0.

To get the property sheet to use a callback function, the dwFlags member of the property sheet header must include the PSH_USECALLBACK flag and the pfnCallback member must point to the callback function (PropSheetProc).

For each of the two property pages a DialogProc callback function is also required. This function handles any messages that are sent to a property page, including those that are initiated by the user clicking on a control. If a message is processed by this function, it must return TRUE (or 1). Otherwise the function returns FALSE (or 0) and the system handles the message. For a property page, this callback function does not call EndDialog at any time, as it would for a normal dialog. The pages are only destroyed when the property sheet is closed.

Since the pages are empty for this example, the DialogProc always returns 0.

The pfnDlgProc member of each PROPSHEETPAGE structure must be set to that pages DialogProc callback procedure.

Note that on my system, a couple of the symbols did not seem to be recognised. One was the PSCB_PRECREATE value. I got an “Error: undefined symbol” message from FASM for this symbol when I tried to compile the code.

The other was the nStartPage member of the PROPSHEETHEADER structure, which also gave the undefined symbol error when I tried to initialise it: mov [psh.nStartPage],0.

This isn’t much of a problem in this case since the members of the structure can be initialised when memory is first allocated for it in the .data section (where nStartPage was already initialised to 0).

; -------------------------------------------------------------------------------------

 format PE GUI 4.0

 entry start

 include 'win32ax.inc'

; -------------------------------------------------------------------------------------

 IDD_PAGE_ONE = 101
 IDD_PAGE_TWO = 102

; -------------------------------------------------------------------------------------

 section '.code' code readable executable

  start:

        stdcall RunPropertySheet

  exit:

        invoke ExitProcess,0

; -------------------------------------------------------------------------------------

proc RunPropertySheet uses ebx esi edi

        ; fill the PROPSHEETHEADER structure (psh)

        ; set the dwFlags member of psh

        mov [psh.dwFlags],PSH_PROPSHEETPAGE+PSH_NOAPPLYNOW+PSH_PROPTITLE+PSH_USECALLBACK

        ; set the dwSize member of psh

        mov [psh.dwSize],psp0-psh

        ; set the hInstance member of psh

        invoke GetModuleHandle,0

        mov [psh.hInstance],eax

        ; set the pszCaption member of psh

        mov [psh.pszCaption],_caption

        ; set the number of pages

        mov [psh.nPages],2

        ; set the pointer to the array of PROPSHEETPAGE structures

        mov [psh.ppsp],psp0

        ; set the pointer to the callback function (PropSheetProc)

        mov [psh.pfnCallback],PropSheetProc


        ; fill the PROPSHEETPAGE structure for the first page (psp0)

        ; set the dwFlags member of psp0

        mov [psp0.dwFlags],PSP_DEFAULT

        ; set the dwSize member of psp0

        mov [psp0.dwSize],psp1-psp0

        ; set the dialog resource to use

        mov [psp0.pszTemplate],IDD_PAGE_ONE

        ; set the dialog box procedure

        mov [psp0.pfnDlgProc],PageOneProc


        ; fill the PROPSHEETPAGE structure for the second page (psp1)

        ; set the dwFlags member of psp1

        mov [psp1.dwFlags],PSP_DEFAULT

        ; set the dwSize member of psp1

        mov [psp1.dwSize],psp1-psp0

        ; set the dialog resource to use

        mov [psp1.pszTemplate],IDD_PAGE_TWO

        ; set the dialog box procedure

        mov [psp1.pfnDlgProc],PageTwoProc


        ; run the property sheet

        invoke PropertySheet,psh

        ret

endp

; -------------------------------------------------------------------------------------

proc PropSheetProc hwnd,uMsg,lParam

        ; property sheet callback function

        ; called when the property sheet is first created and initialised

        ; the PSH_USECALLBACK flag must be set in the PROPSHEETHEADER struct

        ; cmp [uMsg],PSCB_PRECREATE - Error: undefined symbol

        cmp [uMsg],PSCB_INITIALIZED

        jne .DONE

        ; does nothing here

  .DONE:

        ; return 0

        xor eax,eax

        ret

endp

; -------------------------------------------------------------------------------------

proc PageOneProc hwnd,msg,wparam,lparam

        ; the dialog procedure for page one

        ; does nothing here

        ; must not call EndDialog

        ; no messages processed - return 0

        xor eax,eax

        ret

endp

; -------------------------------------------------------------------------------------

proc PageTwoProc hwnd,msg,wparam,lparam

        ; the dialog procedure for page two

        ; does nothing here

        ; must not call EndDialog

        ; no messages processed - return 0

        xor eax,eax

        ret

endp

; -------------------------------------------------------------------------------------

section '.idata' import data readable writeable

  library kernel,'KERNEL32.DLL',\
          comctl32,'COMCTL32.DLL'

  import kernel,\
         GetModuleHandle,'GetModuleHandleA',\
         ExitProcess,'ExitProcess'

  import comctl32,\
         PropertySheet,'PropertySheet'

; -------------------------------------------------------------------------------------

  ; PROPSHEETHEADER:

  ; dwSize,dwFlags,hwndParent,hInstance,hIcon,pszCaption,nPages,nStartPage,ppsp,pfnCallback

  ; PROPSHEETPAGE:

  ; dwSize,dwFlags,hInstance,pszTemplate,hIcon,pszTitle,pfnDlgProc,lParam,pfnCallback,*pcRefParent

; -------------------------------------------------------------------------------------

section '.data' data readable writeable

  psh PROPSHEETHEADER 0,0,NULL,NULL,NULL,NULL,0,0,NULL,NULL

  psp0 PROPSHEETPAGE 0,0,NULL,NULL,NULL,NULL,NULL,0,NULL,NULL

  psp1 PROPSHEETPAGE 0,0,NULL,NULL,NULL,NULL,NULL,0,NULL,NULL

  _caption TCHAR 'Win32 Property Sheet Example -',0

; -------------------------------------------------------------------------------------

section '.rc' resource data readable

  directory RT_DIALOG,dialogs

  ; two dialogs (the property pages) are defined here

  resource dialogs,\
  IDD_PAGE_ONE,LANG_ENGLISH+SUBLANG_DEFAULT,page_one_dlg,\
  IDD_PAGE_TWO,LANG_ENGLISH+SUBLANG_DEFAULT,page_two_dlg

  ; property page ONE

  dialog page_one_dlg,'Page ONE',0,0,260,200,WS_CHILD+WS_CAPTION,0,0

        ; ADD controls here

  enddialog

  ; property page TWO

  dialog page_two_dlg,'Page TWO',0,0,260,200,WS_CHILD+WS_CAPTION,0,0

        ; ADD controls here

  enddialog

; -------------------------------------------------------------------------------------

As already mentioned, the members of the PROPSHEETHEADER and PROPSHEETPAGE structures can be initialised when memory for these structures is allocated in the .data section. If this approach is used, most of the code in the RunPropertySheet procedure can be eliminated:

; -------------------------------------------------------------------------------------

section '.data' data readable writeable

  psh PROPSHEETHEADER psp0-psh,PSH_PROPSHEETPAGE+PSH_NOAPPLYNOW+PSH_PROPTITLE+PSH_USECALLBACK,\
                      NULL,NULL,NULL,_caption,2,0,psp0,PropSheetProc

  psp0 PROPSHEETPAGE psp1-psp0,PSP_DEFAULT,NULL,IDD_PAGE_ONE,NULL,NULL,PageOneProc,0,NULL,NULL

  psp1 PROPSHEETPAGE psp1-psp0,PSP_DEFAULT,NULL,IDD_PAGE_TWO,NULL,NULL,PageTwoProc,0,NULL,NULL

  _caption TCHAR 'Win32 Property Sheet Example -',0

; -------------------------------------------------------------------------------------

proc RunPropertySheet uses ebx esi edi

        ; set the hInstance member of psh (PROPSHEETHEADER)

        invoke GetModuleHandle,0

        mov [psh.hInstance],eax

        ; run the property sheet

        invoke PropertySheet,psh

        ret

endp

; -------------------------------------------------------------------------------------

Example Two

In this second example I add some controls to the property pages. I show how the pages can be initialised upon activation, and how the state of the controls can be captured before a page loses its activation. I also show how the property sheet callback function can be used to customise some aspects of the property sheets appearance.

When the property sheet callback procedure captures the PSCB_PRECREATE message, the lparam argument contains the address of the dialog template for the property sheet in memory. This dialog template is a collection of structures, beginning with either a DLGTEMPLATE or DLGTEMPLATEEX structure. This is system dependent. On my system the dialog template begins with a DLGTEMPLATE structure.

At the beginning of DLGTEMPLATE is the style member, that contains all of the style flags for the property sheet. I modify this member to remove the context help button from the title bar of the property sheet, by XORing DS_CONTEXTHELP into the style value. I then add minimize and maximize boxes by ORing in the WS_MINIMIZEBOX and WS_MAXIMIZEBOX values.

Since PSCB_PRECREATE is not defined on my system, I just define it myself before using it. It has a value of 2.

The other thing I do in the property sheet callback function is capture the messages it receives upon being created. As expected from reading the documentation, it captures two messages with a value of 2 and 1 (PSCB_PRECREATE and PSCB_INITIALIZED). These values are printed to a string which is then displayed in the text box on Page One.

Apart from the text box, Page One also contains some check boxes and radio buttons. When Page One loses its activation, I capture the state of these controls and print them to a string. When Page Two becomes active it displays this string.

To capture the state of the controls on Page One when it loses its activation, I handle the PSN_KILLACTIVE notification in the dialog procedure for Page One. This is sent in the form of a WM_NOTIFY message which is captured by the dialog procedure. When this happens, lparam contains a pointer to a NMHDR structure, containing the member: code. This member will have a value of PSN_KILLACTIVE if the page is about to lose its activation. I can then call my own code to capture the state of the controls and print them to a string. Once this has been done the Win32 function SetWindowLong must then be called to allow the page to lose its activation.

For Page Two to update this status string upon activation, it needs to handle the PSN_SETACTIVE notification in the same way that PSN_KILLACTIVE was handled above. The static text control containing the status of the controls on Page One can then be updated. Finally, SetWindowLong is called to accept the page activation.

; -------------------------------------------------------------------------------------

 format PE GUI 4.0

 entry start

 include 'win32ax.inc'

; -------------------------------------------------------------------------------------

 IDD_PAGE_ONE = 101
 IDD_PAGE_TWO = 102

 IDC_EDIT_1 = 1000
 IDC_BTN_CLEAR = 1001

 IDC_CHK_ONE = 1002
 IDC_CHK_TWO = 1003
 IDC_CHK_THREE = 1004

 IDC_RADIO_ONE = 1005
 IDC_RADIO_TWO = 1006
 IDC_RADIO_THREE = 1007

 IDC_INFO_TEXT = 1008

; -------------------------------------------------------------------------------------

 section '.code' code readable executable

  start:

        stdcall RunPropertySheet

  exit:

        invoke ExitProcess,0

; -------------------------------------------------------------------------------------

proc RunPropertySheet uses ebx esi edi

        ; fill the PROPSHEETHEADER structure (psh)

        ; set the dwFlags member of psh

        mov [psh.dwFlags],PSH_PROPSHEETPAGE+PSH_NOAPPLYNOW+PSH_PROPTITLE+PSH_USECALLBACK

        ; set the dwSize member of psh

        mov [psh.dwSize],psp0-psh

        ; set the hInstance member of psh

        invoke GetModuleHandle,0

        mov [psh.hInstance],eax

        ; set the pszCaption member of psh

        mov [psh.pszCaption],_caption

        ; set the number of pages

        mov [psh.nPages],2

        ; set the pointer to the array of PROPSHEETPAGE structures

        mov [psh.ppsp],psp0

        ; set the pointer to the callback function (PropSheetProc)

        mov [psh.pfnCallback],PropSheetProc


        ; fill the PROPSHEETPAGE structure for the first page (psp0)

        ; set the dwFlags member of psp0

        mov [psp0.dwFlags],PSP_DEFAULT

        ; set the dwSize member of psp0

        mov [psp0.dwSize],psp1-psp0

        ; set the dialog resource to use

        mov [psp0.pszTemplate],IDD_PAGE_ONE

        ; set the dialog box procedure

        mov [psp0.pfnDlgProc],PageOneProc


        ; fill the PROPSHEETPAGE structure for the second page (psp1)

        ; set the dwFlags member of psp1

        mov [psp1.dwFlags],PSP_DEFAULT

        ; set the dwSize member of psp1

        mov [psp1.dwSize],psp1-psp0

        ; set the dialog resource to use

        mov [psp1.pszTemplate],IDD_PAGE_TWO

        ; set the dialog box procedure

        mov [psp1.pfnDlgProc],PageTwoProc


        ; run the property sheet

        invoke PropertySheet,psh

        ret

endp

; -------------------------------------------------------------------------------------

proc PropSheetProc uses edi,hwnd,uMsg,lParam

        ; property sheet callback function

        ; called when the property sheet is first created and initialised

        ; the PSH_USECALLBACK flag must be set in the PROPSHEETHEADER struct

        ; capture the IDs of the messages received by this proc
        ; and store to the array at address PSCB

        lea edi,[PSCB]

        xor eax,eax

        mov al,[index]

        add edi,eax

        mov eax,[uMsg]

        mov [edi],eax

        add [index],4

  .PRECREATE:

        ; define PSCB_PRECREATE (not defined for me)

        PSCB_PRECREATE = 2

        ; process the PSCB_PRECREATE message

        cmp [uMsg],PSCB_PRECREATE

        jne .DONE

        cmp [lParam],0

        je .DONE

        ; assume that lParam points to a DLGTEMPLATE struct

        mov eax,[lParam]

        lea edi,[eax]

        ; modify the DWORD style member, which is the first DWORD in DLGTEMPLATE

        ; remove context help

        xor [edi],dword DS_CONTEXTHELP

        ; add the minimize and maximize boxes

        or [edi],dword WS_MINIMIZEBOX

        or [edi],dword WS_MAXIMIZEBOX

  .DONE:

        ; returns 0

        xor eax,eax

        ret

endp

; -------------------------------------------------------------------------------------

proc PageOneProc hwnd,msg,wparam,lparam

        ; the dialog procedure for page one

        ; must not call EndDialog

        ; initialise return to 0

        xor eax,eax

        cmp [msg],WM_INITDIALOG
        je .ON_INIT_DIALOG

        cmp [msg],WM_COMMAND
        je .ON_COMMAND

        cmp [msg],WM_NOTIFY
        je .ON_NOTIFY

        jmp .DONE

  .ON_INIT_DIALOG:

        stdcall PrintPSCB

        invoke SetDlgItemText,[hwnd],IDC_EDIT_1,bfDisplayStr

        ; return 1 (true)

        mov eax,1

        jmp .DONE

  .ON_COMMAND:

        cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_CLEAR

        je .CLEAR

        jmp .DONE

  .ON_NOTIFY:

        mov eax,[lparam]

        ; get the PSN code from the NMHDR struct

        stdcall GetPSN_Code

        cmp eax,PSN_KILLACTIVE

        je .ON_KILL_ACTIVE

        jmp .DONE

  .ON_KILL_ACTIVE:

        ; get the status of the check boxes and radio buttons

        mov [DlgItemsStatus],dword 0

        invoke IsDlgButtonChecked,[hwnd],IDC_CHK_ONE

        mov [DlgItemsStatus],eax

        invoke IsDlgButtonChecked,[hwnd],IDC_CHK_TWO

        mov [DlgItemsStatus+4],eax

        invoke IsDlgButtonChecked,[hwnd],IDC_CHK_THREE

        mov [DlgItemsStatus+8],eax

        invoke IsDlgButtonChecked,[hwnd],IDC_RADIO_ONE

        mov [DlgItemsStatus+12],eax

        invoke IsDlgButtonChecked,[hwnd],IDC_RADIO_TWO

        mov [DlgItemsStatus+16],eax

        invoke IsDlgButtonChecked,[hwnd],IDC_RADIO_THREE

        mov [DlgItemsStatus+20],eax

        ; print the information to a string

        stdcall PrintDlgItemStatus

        ; allow the page to lose its activation

        invoke SetWindowLong,[hwnd],DWL_MSGRESULT,FALSE

        ; return 1 (true)

        mov eax,1

        jmp .DONE

  .CLEAR:

        ; reset all of the dialog items

        invoke SetDlgItemText,[hwnd],IDC_EDIT_1,""

        invoke UpdateWindow,[hwnd]

        mov [bfDisplayStr],byte 0

        invoke CheckDlgButton,[hwnd],IDC_CHK_ONE,BST_UNCHECKED
        invoke CheckDlgButton,[hwnd],IDC_CHK_TWO,BST_UNCHECKED
        invoke CheckDlgButton,[hwnd],IDC_CHK_THREE,BST_UNCHECKED

        invoke CheckDlgButton,[hwnd],IDC_RADIO_ONE,BST_UNCHECKED
        invoke CheckDlgButton,[hwnd],IDC_RADIO_TWO,BST_UNCHECKED
        invoke CheckDlgButton,[hwnd],IDC_RADIO_THREE,BST_UNCHECKED

        ; return 1 (true)

        mov eax,1

  .DONE:

        ret

endp

; -------------------------------------------------------------------------------------

proc PageTwoProc uses esi edi,hwnd,msg,wparam,lparam

        ; the dialog procedure for page two

        ; must not call EndDialog

        ; initialise return to 0

        xor eax,eax

        cmp [msg],WM_INITDIALOG
        je .ON_INIT_DIALOG

        cmp [msg],WM_NOTIFY
        je .ON_NOTIFY

        jmp .DONE

  .ON_INIT_DIALOG:

        stdcall PrintDlgItemStatus

        invoke SetDlgItemText,[hwnd],IDC_INFO_TEXT,bfInfoStr

        ; return 1 (true)

        mov eax,1

        jmp .DONE

  .ON_NOTIFY:

        mov eax,[lparam]

        ; get the PSN code from the NMHDR struct

        stdcall GetPSN_Code

        cmp eax,PSN_SETACTIVE

        je .ON_SET_ACTIVE

        jmp .DONE

  .ON_SET_ACTIVE:

        invoke SetDlgItemText,[hwnd],IDC_INFO_TEXT,bfInfoStr

        ; accept the activation

        invoke SetWindowLong,[hwnd],DWL_MSGRESULT,0

        ; return 1 (true)

        mov eax,1

  .DONE:

        ret

endp

; -------------------------------------------------------------------------------------

proc GetPSN_Code uses esi

        ; get the PSN code from the NMHDR struct

        ; lparam points to this struct

        ; lparam is passed in eax

        ; load the address of the NMHDR struct

        lea esi,[eax]

        ; the code member is 8 bytes in

        mov eax,[esi+8]

        ret

endp

; -------------------------------------------------------------------------------------

proc PrintDlgItemStatus uses esi edi

  ; print status information about the check box and radio buttons
  ; on page one to the info string

        lea edi,[bfInfoStr]

        ; check box one

        lea esi,[strCheckBox]

        stdcall CopyStringBuffer,9

        lea esi,[strOne]

        stdcall CopyStringBuffer,6

        mov eax,[DlgItemsStatus]

        stdcall PrintItemStatus

        ; check box two

        lea esi,[strCheckBox]

        stdcall CopyStringBuffer,9

        lea esi,[strTwo]

        stdcall CopyStringBuffer,6

        mov eax,[DlgItemsStatus+4]

        stdcall PrintItemStatus

        ; check box three

        lea esi,[strCheckBox]

        stdcall CopyStringBuffer,9

        lea esi,[strThree]

        stdcall CopyStringBuffer,8

        mov eax,[DlgItemsStatus+8]

        stdcall PrintItemStatus

        ; radio one

        lea esi,[strRadio]

        stdcall CopyStringBuffer,6

        lea esi,[strOne]

        stdcall CopyStringBuffer,6

        mov eax,[DlgItemsStatus+12]

        stdcall PrintItemStatus

        ; radio two

        lea esi,[strRadio]

        stdcall CopyStringBuffer,6

        lea esi,[strTwo]

        stdcall CopyStringBuffer,6

        mov eax,[DlgItemsStatus+16]

        stdcall PrintItemStatus

        ; radio three

        lea esi,[strRadio]

        stdcall CopyStringBuffer,6

        lea esi,[strThree]

        stdcall CopyStringBuffer,8

        mov eax,[DlgItemsStatus+20]

        stdcall PrintItemStatus

        ; zero terminate

        mov [edi],byte 0

        ret

endp

; -------------------------------------------------------------------------------------

proc PrintItemStatus

  ; print the status of a check box or radio button to string

  ; status passed in EAX (BST_CHECKED or BST_UNCHECKED)

  ; EDI (the destination string) set outside of this function

        cmp eax,BST_CHECKED

        je .CHECKED

        cmp eax,BST_UNCHECKED

        je .UNCHECKED

        jmp .UNDEFINED

  .CHECKED:

        lea esi,[strChecked]

        stdcall CopyStringBuffer,7

        jmp .DONE

  .UNCHECKED:

        lea esi,[strUnchecked]

        stdcall CopyStringBuffer,9

        jmp .DONE

  .UNDEFINED:

        lea esi,[strUndefined]

        stdcall CopyStringBuffer,9

  .DONE:

        ; add CRLF

        mov [edi],byte 13
        inc edi
        mov [edi],byte 10
        inc edi
        mov [edi],byte 13
        inc edi
        mov [edi],byte 10
        inc edi

        ret

endp

; -------------------------------------------------------------------------------------

proc CopyStringBuffer nBytes

  ; copy a string

  ; nBytes is the number of bytes to copy

  ; ESI and EDI are set outside of this proc

        mov ecx,[nBytes]

  .COPY:

        mov al,[esi]
        mov [edi],al

        inc esi
        inc edi

        loop .COPY

        ret

endp

; -------------------------------------------------------------------------------------

proc PrintPSCB uses esi edi

  ; print the 8 elements of the PSCB array to the display string

        lea edi,[bfDisplayStr]

        lea esi,[PSCB]

        stdcall PrintBuffer,8

        ret

endp

; -------------------------------------------------------------------------------------

proc PrintBuffer nDwords

  ; print a buffer of dwords to a string

  ; nDwords gives the size of the buffer

  ; ESI and EDI are set outside of the function

        mov ecx,[nDwords]

  .NEXT:

        mov eax,[esi]

        stdcall DWordToStr

        mov [edi],byte 32

        inc edi

        add esi,4

        loop .NEXT

        mov [edi],byte 0

        ret

endp

; -------------------------------------------------------------------------------------

proc DWordToStr

  ; print a dword (4 bytes) to a string

  ; word passed in EAX

  ; EDI is set outside of this function

        locals

          tmp dw 0

        endl

        mov word [tmp],ax

        shr eax,16

        stdcall WordToStr

        mov ax,word [tmp]

        stdcall WordToStr

        ret

endp

; -------------------------------------------------------------------------------------

proc WordToStr uses edx

  ; print a word (2 bytes) to a string

  ; word passed in AX

  ; EDI is set outside of this function

        mov dx,ax
        mov al,ah

        stdcall ByteToDigits

        mov [edi],ah
        inc edi

        mov [edi],al
        inc edi

        mov al,dl

        stdcall ByteToDigits

        mov [edi],ah
        inc edi

        mov [edi],al
        inc edi

        ret

endp

; -------------------------------------------------------------------------------------

proc ByteToDigits uses ebx esi edi

  ; convert 1 byte to 2 hex digits

  ; input in AL - output in AX

        ; copy AL to AH

        mov ah,al

        ; AH: get the upper 4 bits of the byte

        shr ah,4

        ; nibble to hex digit

        add ah,48

        cmp ah,57

        jle .NEXT

        add ah,7

  .NEXT:

        ; AL: get the lower 4 bits of the byte

        and al,0xf

        ; nibble to hex digit

        add al,48

        cmp al,57

        jle .DONE

        add al,7

  .DONE:

        ; output is in AX

        ret

endp

; -------------------------------------------------------------------------------------

section '.idata' import data readable writeable

  library kernel,'KERNEL32.DLL',\
          comctl32,'COMCTL32.DLL',\
          user,'USER32.DLL'

  import kernel,\
         GetModuleHandle,'GetModuleHandleA',\
         ExitProcess,'ExitProcess'

  import comctl32,\
         PropertySheet,'PropertySheet'

  import user,\
        SetDlgItemText,'SetDlgItemTextA',\
        GetDlgItemText,'GetDlgItemTextA',\
        IsDlgButtonChecked,'IsDlgButtonChecked',\
        CheckDlgButton,'CheckDlgButton',\
        UpdateWindow,'UpdateWindow',\
        SetWindowLong,'SetWindowLongA'

; -------------------------------------------------------------------------------------

  ; PROPSHEETHEADER:

  ; dwSize,dwFlags,hwndParent,hInstance,hIcon,pszCaption,nPages,nStartPage,ppsp,pfnCallback

  ; PROPSHEETPAGE:

  ; dwSize,dwFlags,hInstance,pszTemplate,hIcon,pszTitle,pfnDlgProc,lParam,pfnCallback,*pcRefParent

; -------------------------------------------------------------------------------------

section '.data' data readable writeable

  psh PROPSHEETHEADER 0,0,NULL,NULL,NULL,NULL,0,0,NULL,NULL

  psp0 PROPSHEETPAGE 0,0,NULL,NULL,NULL,NULL,NULL,0,NULL,NULL

  psp1 PROPSHEETPAGE 0,0,NULL,NULL,NULL,NULL,NULL,0,NULL,NULL

  _caption TCHAR 'Win32 Property Sheet Example -',0

  PSCB dd 0,0,0,0,0,0,0,0

  index db 0

  bfDisplayStr rb 200

  bfInfoStr rb 200

  DlgItemsStatus dd 0,0,0,0,0,0

  strChecked db "CHECKED"
  strUnchecked db "UNCHECKED"
  strUndefined db "UNDEFINED"
  strCheckBox db "CheckBox "
  strRadio db "Radio "
  strOne db "One:  "
  strTwo db "Two:  "
  strThree db "Three:  "

; -------------------------------------------------------------------------------------

section '.rc' resource data readable

  directory RT_DIALOG,dialogs

  ; two dialogs (the property pages) are defined here

  resource dialogs,\
  IDD_PAGE_ONE,LANG_ENGLISH+SUBLANG_DEFAULT,page_one_dlg,\
  IDD_PAGE_TWO,LANG_ENGLISH+SUBLANG_DEFAULT,page_two_dlg

  ; property page ONE

  dialog page_one_dlg,'Page ONE',0,0,260,200,WS_CHILD+WS_CAPTION,0,0

    dialogitem 'EDIT',0,IDC_EDIT_1,13,18,230,100,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0

    dialogitem 'BUTTON','Groupbox',-1,13,140,180,50,BS_GROUPBOX+WS_VISIBLE,0

    dialogitem 'BUTTON',"Check Box One",IDC_CHK_ONE,13,124,80,10,BS_AUTOCHECKBOX+WS_TABSTOP+WS_VISIBLE,0
    dialogitem 'BUTTON',"Check Box Two",IDC_CHK_TWO,93,124,80,10,BS_AUTOCHECKBOX+WS_TABSTOP+WS_VISIBLE,0
    dialogitem 'BUTTON',"Check Box Three",IDC_CHK_THREE,173,124,80,10,BS_AUTOCHECKBOX+WS_TABSTOP+WS_VISIBLE,0

    dialogitem 'BUTTON',"Radio One",IDC_RADIO_ONE,20,152,80,10,BS_AUTORADIOBUTTON+WS_TABSTOP+WS_VISIBLE,0
    dialogitem 'BUTTON',"Radio Two",IDC_RADIO_TWO,20,164,80,10,BS_AUTORADIOBUTTON+WS_TABSTOP+WS_VISIBLE,0
    dialogitem 'BUTTON',"Radio Three",IDC_RADIO_THREE,20,176,80,10,BS_AUTORADIOBUTTON+WS_TABSTOP+WS_VISIBLE,0

    dialogitem 'BUTTON',"Clear",IDC_BTN_CLEAR,207,174,36,14,BS_PUSHBUTTON,0

  enddialog

  ; property page TWO

  dialog page_two_dlg,'Page TWO',0,0,260,200,WS_CHILD+WS_CAPTION+WS_VISIBLE,0,0

    dialogitem 'BUTTON','Info',-1,13,5,230,180,BS_GROUPBOX+WS_VISIBLE,0
    dialogitem 'STATIC',"Text",IDC_INFO_TEXT,23,20,210,160,SS_LEFT+WS_GROUP+WS_VISIBLE,0

  enddialog

; -------------------------------------------------------------------------------------
About these ads

The Silver is the New Black Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: