SysInfo |
Abstract |
This sample demonstrates the following: Creating a dialog with the GUI Builder Working with resources Creating a project and generating an executable Using external resource scripts Integrating Resource Compilation This page contains step-by-step instructions on how to implement a complete dialog-based application that uses resources and a custom icon. |
Additional topics: Control reframing, separating development-time and runtime code |
Click on File|Browse Classes to open a Class Hierarchy Browser on the dialog. Add the code that fills the tree view to the initWindow method.
Create a folder with the application name. Here, the application name is SysInfo, so you create a SysInfo folder that will hold the project and resources.
Generate a resource script
Open the GUI Builder, click on File|New and select Resource Script. Select the parent directory (SysInfo) into which you want the resources to be placed. The builder will create a Res subdirectory under the specified folder.
In the check prompter, check
Click Ok to generate the files:
File | Description |
dummy.def | Dummy file required to compile a resource DLL |
makefile | Makefile for NMAKE |
stmsg.bin | Message file |
sysinfo.ico | Application icon |
sysinfo.rc | Resource script |
You can now run nmake in the res subdirectory to build the resource DLL.
Open the Project Browser and drag the dialog class to the project contents pane. Save the project under the SysInfo folder.
Create a winmain.sm method that defines the entry point for your application:
!ApplicationProcess * methods!
winMain: hModule with: hPrevInstance with: cmdLineArgs with: nCmdShow
"
Public - Calls initialization function.
"
" init common controls if we use them "
WINAPI InitCommonControls.
" initialize COM "
IClassFactory coInitialize.
" open a modal dialog "
SystemInfoDialog new openOn: 0.
" uninitialize COM "
IClassFactory coUninitialize.
! !
The first line initializes the common control library (otherwise the TreeView could not be created). The second line initialize COM (the system info class uses COM to query properties). Finally, the third line opens the dialog. On exit we uninitialize COM.
You can now build and test the executable.
Once the dialog is stable, generate an RC file as follows:
The builder generates the file dialog.rc and modifies the dialog class so that it loads the dialog from the resource rather than from the in-memory template. The #initTemplate method is not used anymore.
Add the line below to the resource script SysInfo.rc:
RCINCLUDE dialog.rc
This line includes the dialog resource into the resource DLL. You can now recompile the DLL using NMAKE. When you build the executable, the dialog is loaded from the compiled resource.
After performing the steps above, the dialog works in the executable but not anymore in the development image, because the dialog attempts to load the resource DLL from the current module (which is stdev.dll by default). The solution is to load the resource DLL in the initialize method:
initialize
m_module := HModule loadLibrary: 'sysinfo.dll'.
^super initialize
After adding the method the dialog loads in the development image but will require sysinfo.dll at runtime, so clearly we don't want to execute this code at runtime. One possibility is to use conditional statements:
_IS_DEVELOPMENT == TRUE ifTrue: [
m_module := HModule loadLibrary: 'sysinfo.dll'.
]
The constant _IS_DEVELOPMENT is set to 1 (TRUE) in the development image and to 0 at runtime. The compiler optimizes the statement so that at development, the code is the same as in our first initialize method. At runtime the initialize method becomes:
initialize
^super initialize
Obviously the code to which the #initialize method defaults at runtime is not very useful, the best would be to remove it entirely. This is what the category .INTERNALDEV does: any method under this category is excluded from runtime.
Therefore, the solution in this case is to set the #initialize category to .INTERNALDEV. However, if you performed other initializations in the method you would have to use the _IS_DEVELOPMENT test to separate runtime and development-only code.
To add a custom icon and / or menu to a dialog, you must first register the dialog class.
Registering the window class
This is done using the message #registerClass:. Behind the scenes, the implementation for dialog boxes is a little different. The registration code in DialogBox queries the parameters for the default dialog class, then replaces the icon, sets a new class name and registers the class.
Add the following methods:
registerClass
|hmod|
hmod := HModule loadLibrary: 'sysinfo.dll'.
self registerClass: hmod.
hmod close.
This method registers the class in the development environment. At runtime, this method is not called so we place it under the .INTERNALDEV category. The startup code in winmain.sm performs the registration at runtime:
!ApplicationProcess * methods!
winMain: hModule with: hPrevInstance with: cmdLineArgs with: nCmdShow
"
Public - Calls initialization function.
"
" init common controls if we use them "
WINAPI InitCommonControls.
" initialize COM "
IClassFactory coInitialize.
" register window class "
SystemInfoDialog registerClass: hModule.
" open a modal dialog "
SystemInfoDialog new openOn: 0.
" uninitialize COM "
IClassFactory coUninitialize.
! !
windowClassIcon
^IDI_APP
windowClassName
^'SysInfo'
Modifying the dialog template
The dialog template must specify the class name, which is done by adding the CLASS statement to the RC script:
IDD_DIALOG1 DIALOGEX 0, 0, 301, 169
STYLE WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_VISIBLE|DS_MODALFRAME|DS_NOIDLEMSG|DS_SETFONT
CAPTION "System Info"
CLASS "SysInfo"
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "",IDC_LIST1, "SysTreeView32", WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT, 7,6,289,156,
END
By default, the builder binds the resources in the DLL in the Res subdirectory, if one is present. You can direct the builder to automatically build the DLL:
This also has the advantage of generating a new message file with SysInfo (the application name entered into the edit box) as the aplication title.