In this post I use FASM (the Flat Assembler) to implement Win32 Property Sheets in x86 assembly language.
Related Posts
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 ; ------------------------------------------------------------------------------------- |