Platform SDK Tools

The following are tools contained in the Microsoft® Platform Software Development Kit (SDK).

Cryptography

Tool | Description
Cert2SPC | Creates a test software publisher certificate.
CertMgr | Manages certificates, certificate trust lists, and certificate revocation lists.
ChkTrust | Checks validity of signed file.
MakeCat | Creates a catalog file.
MakeCert | Creates an X.509 certificate.
MakeCTL | Creates a certificate trust list.
SetReg | Sets registry values to control the certificate verification process.
SignCode | Signs a file.

Debugging

Tool | Description
AlphaKD | Symbolic Debuggers
DBMon | Using Debug Monitor
DBWin | Using Windows Debug Monitor
DDESpy | Monitoring Messages and Data
DumpChk | System Crash Dump
DumpRef | System Crash Dump
HeapWalk | Using Heap Walker
HW32 | Using Heap Watch
I386KD | Symbolic Debuggers
MapSym | Using MAPSYM
NTSD | Symbolic Debuggers
SPY | Monitoring Messages and Data
WDeb386 | WDEB386 Debugger
WinDbg | WinDbg Debugger
WinObj | Using Object Viewer

DirectX

Tool | Description
Conv3ds | Converts 3-D models produced by modeling packages to the DirectX file format.
DxCapsViewer | Enumerates devices and capabilities for all components of DirectX.
DxDiag | A diagnostic tools that gathers information on the system and the DirectX components installed on it.
DxTex | Creates texture maps that use the DXTn compression formats.
GraphEdt | Creates and tests filter graphs.

MAPI

Tool | Description
ABView32 | An address book viewer.
MDBVU32 | A message store viewer.
PropVU32 | A property viewer.
StatVU32 | A status table viewer.
TblVU32 | A table viewer.

Multimedia

Tool | Description
AVIEdit | AVI editor
CapScrn | Capture screen
DDTest DDTest32 | DrawDib test
IDFEdit | IDF editor
RIFFAdd | RIFF add
RIFFWalk | RIFF walk
VidCap VidCap32 | Video capture

OLE

Tool | Description
DFLayout | Compound File Layout Tool
DFView | Doc File Viewer
DObjView | Data Object Viewer
IROTView | Running Object Table Viewer
MIDL | Using the MIDL Compiler
MkTypLib | MkTypLib: Type Library Creation Tool
OLEView | Using OleView
RegSvr32 | Register Server
UUIDGen | Generating Interface UUIDs

Resource Files

Tool | Description
DLGEdit | Dialog Box Editor
FontEdit | Font Editor
HCW | Help Compiler
ImagEdit | Image Editor
MC | Message Compiler
MRBC | Multiple-Resolution Bitmap Compiler
RC | Resource Compiler
RLMan | Localizing Resources
SHED | Hotspot Editor
UConvert | Localizing Resources

TAPI

Tool | Description
ExtIDGen | Extension ID generator
RepApp | Repeater application
RepSetup | Repeater setup
TB13 | TAPI 1.3 browser
TB14 | TAPI 1.4 browser
TB20 | TAPI 2.0 browser
TB3X | TAPI 3.0 browser

Testing

Tool | Description
CPUStres | CPU stress
PfMon | Process fault monitor
SC | Service control
Stress | Stress

Text Files

Tool | Description
EXP | Microsoft Editor
MEP | Microsoft Editor
QGrep | Managing Files
RM | Microsoft Editor
Undel | Microsoft Editor
Where | Managing Files
WinDiff | Managing Files

Tuning

Tool | Description
APIMon | API monitor
Bind | Minimizes application load time.
CAPDump | Call attributed profiler
CAPSetup | Call attributed profiler
CAPStats | Call attributed profiler
CAPView | Call attributed profiler
ExCtrLst | Extensible counter list utility
MemSnap | Memory Snapshot
PerfMtr | Performance meter
Profile | Sampling profiler
PStat | Performance statistics
PView | Performance viewer
PWalk | Process walker
Rebase | Rebase
VADUMP | Virtual address dump
WPerf | Performance monitor
WSTCat | Working set tuner
WSTDump | Working set tuner
WSTune | Working set tuner

Windows Sockets

Tool | Description
SPOrder | Service provider ordering

Microsoft Platform SDK, February 2001 Edition.
This content last built on Wednesday, February 07, 2001.


Monitoring Messages and Data

Spy (SPY.EXE) and DDESpy (DDESPY.EXE) are monitoring tools for the Microsoft® Windows® operating system. Spy makes it possible for you to monitor messages sent to one or more windows and to examine the values of message parameters. DDESpy lets you monitor dynamic data exchange (DDE) activity.

This overview describes the use of both Spy and DDESpy.


Spy

This section describes how to use the following menus to specify how Spy is to operate:

  • The Spy menu
  • The Edit menu
  • The Options menu
  • The Start!/Stop! menu


The Spy Menu

Use the Spy menu to select the window you want Spy to monitor. The Spy menu contains the following commands:

Commands

Select Window
Specifies the window that Spy is to monitor. By default, all windows are selected. When you choose the Window command, Spy displays the Spy Window dialog box. This dialog box displays information about the window in which the cursor is located. As you move the cursor from window to window, the following information is updated:
Item | Description
Window | Handle of the window.
Class | Window class.
Parent | Handle of the parent window and the name of the program that created the parent window.
Rect | Upper-right and lower-left coordinates of the window and the window size in screen coordinates.
Style | Style bits of the window in which the cursor is located, the principal style of the window, and an identifier if the window is a child window. The principal style can be WS_POPUP, WS_ICONIC, WS_OVERLAPPED, or WS_CHILD.
All Windows | Specifies that Spy is to display messages received by all windows.

About
Provides information about the version of Spy you are using.
Exit
Closes Spy.


The Edit Menu

You can use the Edit menu to Cut, Copy, and Clear information from the Spy window to the clipboard.

Command | Description
Cut | Cuts the selected text to the clipboard.
Copy | Copies the selected text to the clipboard.
Clear | Clears the selected text from the Spy window.


The Options Menu

The Options menu displays a dialog box in which you can do the following tasks:

  • Selecting the message types Spy is to monitor.
  • Selecting the font Spy is to use.
  • Selecting the output device Spy is to send messages to.

You make your selections from items displayed under Messages, Font, and Output.


Selecting the Message Types

Under Messages, you can select any of the following message types you want Spy to monitor:

Message type | Description
DDE | Dynamic data exchange (DDE) messages, such as WM_DDE_REQUEST
Clipboard | Clipboard messages, such as WM_RENDERFORMAT
Mouse | Mouse messages, such as WM_MOUSEMOVE and WM_SETCURSOR
Non Client | Windows nonclient messages, such as WM_NCDESTROY and WM_NCHITTEST
Keyboard | Keyboard messages, such as WM_KEYDOWN and WM_ACTIVATE
Button Control | Button control messages, such as BN_CLICKED and BM_GETCHECK
Combo Box Control | Combo Box control messages, such as CB_ADDSTRING and CB_LIMITTEXT
Edit Control | Edit control messages, such as EM_GETSEL and EM_UNDO
List Box Control | List box control messages, such as LB_GETSEL and LB_GETCARETINDEX
Static Control | Static control messages, such as STM_GETICON and WM_CTLCOLORSTATIC
WM_USER | Application-defined messages
Unknown | Messages other than those explicitly listed

By default, Spy monitors all messages.


Selecting the Font

Under Font, you can select which font you would like Spy to use in its window. This dialog box allows you to choose the font name, font style and point size, and displays a sample of the font you have chosen.


Selecting the Output Device

Under Output, you can select which of the following output devices you want Spy to send messages to:

Device | Description
Window | Spy displays messages in the Spy window. You can specify how many messages Spy stores in its buffer. By default, Spy stores up to 250 lines of messages, which you can view by scrolling through the Spy window. You can also change the maximum number of lines that can be stored in the buffer.
Com1 | Spy sends messages to the COM1 port.
File | Spy sends messages to the specified file. The default output file is SPY.LOG.


The Start!/Stop! Menu

After using the Options and Spy menus to make your selections, start Spy by clicking the Start! menu.

To stop monitoring messages, click the Stop! menu.


DDESpy

DDESpy is a typical DDE monitoring application. Because DDE is a cooperative activity, DDE monitoring applications must follow certain guidelines for your Windows system to operate properly while they are in use. In particular, DDE monitoring applications should not perform DDE server or client communications — problems may arise when the monitoring application intercepts its own communications. For more information about DDE, see Dynamic Data Exchange.

This section describes how to use the following menus to specify how DDESpy is to operate:

  • The Output menu
  • The Monitor menu
  • The Track menu
  • The About menu


The Output Menu

DDESpy can display DDE information in a window or on your debugging terminal or can save the displayed information in a file for later use.

You use the Output menu to select where DDESpy is to send output. If you choose the File command, you must specify the name of an output file. After you have chosen the File command once, DDESpy prompts you for an output filename every time you restart the application.

From the Output menu, you can choose to send your output to either a debug terminal or to the DDESpy window. You can also choose the Clear Screen command to clear the display window. Use the Mark command to add text to the display as a marker — for example, before a DDE event to make it easier to find the event in the output file.


The Monitor Menu

You use the Monitor menu to specify one or more types of DDE information that DDESpy is to display. The following tasks can be specified:

  • Monitoring string handle data
  • Monitoring posted DDE messages
  • Monitoring callbacks
  • Monitoring Errors

You can use the Filters option to choose the type of DDE messages and types of DDE callbacks to monitor.

The DDE protocol passes information by using shared memory. The contents of the shared memory depend on the type of DDE transaction. Several structures have been defined to allow applications using DDE to access the information in shared memory. DDESpy displays the contents of the appropriate structure for the DDE activity being monitored.


Monitoring String-Handle Data

The DDE protocol uses the MONHSZSTRUCT structure to pass string-handle data. DDESpy displays the following information from this structure:

  • Task (application instance)
  • Time, in milliseconds, since you started Windows
  • Activity type (create, destroy, or increment)
  • String handle
  • String contents

The following example shows a typical DDESpy display of string-handle data:

Task:0x94f, Time:519700, String Handle Created: c4a4(this is a test)
Task:0x94f, Time:526126, String Handle Created: c4aa(another test)


Monitoring Posted DDE Messages

The DDE protocol uses the MONMSGSTRUCT structure to post DDE messages. DDESpy displays the following information from this structure:

  • Task
  • Time
  • Handle of receiving window
  • Transaction type (sent or posted)
  • Message type
  • Handle of sending application
  • Other message-specific information

The following example shows a typical DDESpy display of DDE message activity:

Task:0x8df Time:642402 hwndTo=0x38dc Message(Sent)=Initiate:
       hwndFrom=9224, App=0xc35d("Server")
       Topic=*
Task:0x94f Time:642457 hwndTo=0x2408 Message(Sent)=Ack:
       hwndFrom=9396, App=0xc35d("Server")status=c35d(fAck fBusy )
       Topic=Item=0xc361("System")


Monitoring Callbacks

The DDE protocol uses the MONCBSTRUCT structure to pass information to application callback functions. DDESpy displays the following information from this structure:

  • Task
  • Time
  • Transaction type
  • Exchanged-data format, if any
  • Conversation handle
  • String handles and their referenced strings
  • Transaction-specific data

The following example shows a typical DDESpy display of callback activity:

Task:0x8df Time:2882628 Callback:
       Type=Advstart, fmt=0x1("CF_TEXT"), hConv=0xc24b4,
       hsz1=0xc361("System") hsz2=0xc4df("xxcall"), hData=0x0,
       lData1=0x83f0000, lData2=0x0
       return=0x0


Monitoring Errors

When an error occurs during a DDE transaction, the DDE protocol places the error value and associated information in a MONERRSTRUCT structure. DDESpy uses this structure to display the following information about the error:

  • Task (the handle of the application that caused the error)
  • Time
  • Error value and name


The Track Menu

DDESpy can also display information about aspects of DDE communication in your Windows system through the following means:

  • Tracking string handles
  • Tracking conversations
  • Tracking links
  • Tracking services

You can use the Track menu to specify which DDE activity DDESpy is to track. When you choose a command from the Track menu, DDESpy creates a separate window for the display of information in conjunction with the DDE functions. For each window created, DDESpy updates the displayed information as DDE activity occurs. Events that occurred prior to creation of the tracking window are not displayed in the tracking window.

DDESpy can sort the displayed information in the tracking window. If you select the heading for a particular column in the tracking window, DDESpy will sort the displayed information based on the column you selected. This can be useful if you are searching for a particular event or handle.


Tracking String Handles

Windows maintains a system-wide string table containing the string handles that applications use in DDE transactions. To display the system string table so that the string, the string handle, and the string usage count are shown, choose the String Handles command from the Track menu.


Tracking Conversations

To see a display of all active DDE conversations in your Windows system, choose the Conversations command from the Track menu. The Conversations window shows the service name, the current topic, and the server and client handles for each active conversation.


Tracking Links

To see a display of all active DDE advise loops, choose the Links command from the Track menu. The Links window shows the server name, topic, item format, transaction type, client handle, and server handle for every active advise loop in your Windows system.


Tracking Services

Server applications use the DdeNameService function to register with the DDE protocol. When the DDE protocol receives the DdeNameService function call, it adds the server name and an instance-specific name to a list of registered servers. To see a list of registered servers, choose the Services command from the Track menu.


The About Menu

The About menu displays a dialog box containing information about the version of DDESpy that you are using.


Symbolic Debuggers

The NTSD debugger allows you to debug user-mode applications on Microsoft® Windows NT®/Windows® 2000. You can display and execute program code, set breakpoints, and examine and change values in memory.

The kernel debugger (KD) allows you to debug kernel-mode device drivers. It provides assembly language debugging and is intended for system developers and device driver writers.

The symbolic debuggers are installed when you install the developer tools included with the Platform SDK. For more information on the debuggers, see the help file included with NTSD and KD.


WinDbg Debugger

The WinDbg debugger is a powerful, graphical tool that allows you to debug Win32®-based applications on Microsoft® Windows NT®/Windows® 2000 and Windows® 95/98. You can also use the integrated text editor to edit your source code.

Windows NT/Windows 2000: You can also use WinDbg to debug service applications and kernel-mode drivers.

Note To debug a 16-bit application, use a 16-bit debugger, such as the one included in Microsoft Visual C++® version 1.5.

The WinDbg files are installed when you install the developer tools included with the Platform SDK. For information on using WinDbg, see the help file windbg.hlp, which is included with WinDbg.

The latest version of WinDbg is also available for download on http://www.microsoft.com/ddk/debugging/.


Debug Utilities

The Platform SDK contains several useful debug utilities. They are discussed in the following topics:

  • Using Debug Monitor
  • Using Windows Debug Monitor
  • Using Heap Watch
  • Using Heap Walker
  • Using MAPSYM
  • Using Object Viewer
  • System Crash Dump


Using Debug Monitor

Windows NT/Windows 2000

The Debug Monitor (DBMON.EXE) runs in its own console window and displays messages sent by your application using the OutputDebugString function.


Using Windows Debug Monitor

Windows 95/98

The Windows Debug Monitor (DBWIN.EXE) displays debug messages sent by your application and by the system DLLs. By default, output is sent to the DBWIN window. You can change this default by clicking either Output to COM1 or Output to COM2 from the Options menu.

To control the types of messages that are displayed, click Settings from the Options menu, and select the messages to view.


Using Heap Watch

Windows 95/98

Heap Watch (HW32) lets you view application heaps and monitor them for memory leaks. The Summary-view window shows a list of the heaps for all active Win32-based applications. The Details-view window shows all memory objects in the selected heap. The Object-view window shows the blocks of memory that were allocated for the given object.

The following is the command-line syntax for HW32:

hw32 [-la LogFile] [-lh Logfile] [-aa MS] [-ah MS]
-la LogFile
The name of the log file used to store heap information when you click Update from the Summary-view window.
-lh LogFile
The name of the log file used to store heap information when you click Update or Snapshot from the Detail-view window.
-aa MS
Summary-view window snapshot interval, in milliseconds.
-ah MS
Details-view window snapshot interval, in milliseconds.

HW32 is useful for viewing memory objects and watching for memory leaks, as shown in the following procedures:

To View a Given Memory Object

  1. From the Summary-view window, double-click the heap you want to watch. This displays up the Details-view window.
  2. From the Details-view window, double-click the address in the heap that you with to view.

To Watch For Memory Leaks

  1. From the Summary-view window, double-click the heap you want to watch. This displays the Details-view window.
  2. Perform the operation that you believe causes the memory leak.
  3. Click Snapshot from the Details-view window. The snapshot count is incremented. Allocations that occurred during this snapshot and still exist are possible candidates for a memory leak.
  4. Look for allocated memory objects that belong only to the current snapshot. Objects that belong to the current snapshot are automatically placed at the top of the list


Using Heap Walker

Windows 95/98

The Heap Walker (HEAPWALK.EXE) lets you examine the global heap (the system memory that Windows 95 uses) and local heaps used by active applications and DLLs. Heap Walker is useful for analyzing the effects your application has when it allocates memory from the global heap or when it creates user interface objects or graphics objects.


Using MAPSYM

Windows 95/98

MAPSYM converts the contents of your application's symbol map (.MAP) file into a form suitable for loading with the Microsoft Windows 80386 Debugger (WDEB386.EXE). MAPSYM then copies the result to a symbol (.SYM) file.

The following is the command-line syntax for MAPSYM:

mapsym [/l] [/n] MapFileName
/l
Directs MAPSYM to display information on screen about the conversion. The information includes the names of groups defined in the application, the application start address, the number of segments, and the number of symbols per segment.
/n
Directs MAPSYM to ignore line-number information in the map file. The resulting symbol file contains no line-number information.
MapFileName
Specifies the filename for the symbol file that was creating during linking. If you do not give a filename extension, .MAP is assumed. The new symbol file will use the same base filename as MapFileName, but with the .SYM extension.


Using Object Viewer

Windows NT/Windows 2000

The Object Viewer (WINOBJ.EXE) lists all the objects in the system. For certain object types, you can double-click on its icon to get more information, such as description, attributes, and resource usage.


System Crash Dump

Windows NT/Windows 2000

The Platform SDK contains two tools that you can use with the system crash dump files produced by Windows NT/Windows 2000 and the Dr. Watson utility. DUMPCHK is a command-line utility that you can use to verify that a dump file has been created correctly. DUMPCHK does not require access to symbols. DUMPREF is a command-line utility that you can use to make a reference to a system crash dump file that can be easily used by a remote debugger. This reference contains the location of the crash dump file and the symbols.

The following is the command-line syntax for DUMPCHK:

dumpchk [-v] [-p] [-q] CrashDumpFile
-v
Verbose mode.
-p
Print header only; perform no validation.
-q
Perform a quick test.
CrashDumpFile
The crash dump file.

The following is the command-line syntax for DUMPREF:

dumpref [-d DestFile] SourceFile SymbolPath
-d DestFile
Specifies the destination dump file name, DestFile.
SourceFile
The system crash dump file.
SymbolPath
The path to the symbol files.


WDEB386 Debugger

The Microsoft® Windows® 80386 Debugger (WDEB386.EXE) is used to test and debug Windows-based applications, dynamic-link libraries (DLL), and virtual device drivers (VxDs) on Windows 95/98. Using the WDEB386 commands, you can inspect and manipulate test code and environment status, install breakpoints, and perform other debugging operations.

  • Using WDEB386
  • WDEB386 Debugger


Using WDEB386

Before you start WDEB386, you must prepare for debugging by doing the following:

  • Connect a serial terminal or other computer to the serial port on your debugging computer.
  • Create symbols files for the application, DLL, or VxD you intend to debug. See Using MAPSYM.
  • Install the debugging versions of the system DLLs and VxDs. These files are available in the Windows 95 Device Driver Development Kit (DDK).

The following is the command-line syntax for WDEB386:

wdeb386 [/A] [/B] [/C:comport] [/D:"commands"]
 [/E] [/F:filename] [/H] [/I] [/L] [/N] [/R:dddd]
 [/T:hhhh] [/S:symfile] [/V[P]] [/X] winfile [parameters]

Options

/A
Specifies that symbol files should not be automatically loaded.
/B
Specifies that the debugger should stop just prior to VMM initialization, after all virtual devices have been loaded and the processor is running in protected mode.
/C:comport
Specifies a COM port for debugger output. You can specify "1", "2", "3", or "4" for comport. If this option is not specified, The debugger checks first for COM2. If COM2 is not found, the debugger then checks for COM1. If neither COM1 nor COM2 exists, the debugger checks for any other COM port in the read-only memory (ROM) data area (40:0).
/D:"commands"
Carries out the debugger command line specified by the string enclosed in quotation marks after symbols are loaded. Spaces, semicolons (;), and other punctuation can be included in the command string. To use a single quote (') on the command line, use double quotation marks (") before and after the single quotation mark.
/E
Specifies that the debugger should stop at real-mode entry.
/F:filename
Specifies a file containing command-line options for the debugger. Maximum file size is 4K, and the input file cannot contain the /F option.
/H
Specifies that the debugger should be loaded as a VxD.
/I
Specifies that the debugger should be invisible to int 41.
/L
Specifies that line numbers should not be included in the .SYM file. This can make a large difference in memory use, and may be required on a machine with 4 megabytes of RAM.
/N
Sets the following options:

dislwr

codebytes

symaddrsint3line

newvec

newreg

newprompt

For more information, see the y command.

/R:dddd
Sets the baud rate for the debugging terminal.
/S:symfile
Specifies a symbol file to be loaded. This option can be repeated to load more than one symbol file. If the symbol files are not in your current directory, you must supply a full path, because the debugger does not use the PATH environment variable to locate any of the files supplied on the command line.
/T:hhhh
Sets the port number for the timing card. The default is 0250h.
/V
Enables verbose mode, which displays messages indicating which segments are being loaded.
/VP
Enables verbose mode, which displays messages indicating which application segments are being loaded.
/X
Causes symbols to be loaded into Extended Memory Specification (XMS) memory.
winfile
Specifies the Windows application to run under debugger control. You will usually specify WIN.COM.
parameters
Specifies any parameters to be passed to the application.


WDEB386 Commands

The following are the commands supported by WDEB386.

? (Help)
? (Evaluate Expression)
.<dev_name> (Dot Device)
.? (Help)
.b (Baud Rate)
.df (Display Free Memory)
.dg (Display Global Memory)
.dh (Display Local Heap)
.dm (Display Modules)
.dq (Display Task Queues)
.ds (Dump Stack)
.du (Display Least Recently Used)
.m (Memory)
.reboot (System Restart)
.v (Virtual Machine Commands)
.vmm (Display VMM Commands)
.w (Display Win32 Object)
bc (Breakpoint Clear)
bd (Breakpoint Disable)
be (Breakpoint Enable)
bl (Breakpoint List)
bp (Breakpoint)
br (Breakpoint Register)
c (Compare)
d (Display)
da (Display ASCII)
db (Display Bytes)
dd (Display Doublewords)
dg (Display GDT)
di (Display IDT)
dl (Display LDT)
dp (Display Page Directory and Tables)
dt (Display Task State Segment)
dw (Display Words)
dx (Display Loadall Buffer)
e (Enter)
f (Fill)
g (Go)
h (Hex)
i (Input)
j (Conditional)
k (Stack Trace)
ka (Stack Trace Arguments)
kt (Stack Trace for Task)
la (List Absolute Symbols)
lg (List Groups)
lm (List Maps)
ln (List Nearest Symbol)
ls (List Symbols)
lse (List Symbols by Regular Expression)
m (Move)
o (Output)
p (Program Trace)
r (Register)
s (Search)
t (Trace)
u (Disassemble)
v (Version Number)
vc (Vector Clear)
vl (Vector List)
vo (Vector List New)
vs (Vector Trap Non-Supervisor)
vt (Vector Trap)
w (Change Map)
wa (Activate Map)
wr (Deactivate Map)
x (Dump Debug Report)
y (Debugger Options)
z (Zap)
zd (Execute Default)
zl (Display Default)
zs (Set Default)


? (Help)

The ? command with no arguments displays a list of commands and syntax recognized by the debugger.

?


? (Evaluate Expression)

The ? command evaluates an expression and displays the result.

? [option.]expr
? "string", expr, ...

Parameters

expr
Specifies the expression to evaluate. Can be a combination of numbers, addresses, and operators. Numbers are assumed to be hexadecimal. Addresses can be 32-bit physical addresses or protected-mode addresses (selector:offset). The number sign (#) operator overrides the current address type. Operators can be any listed in Binary and Unary Operators.
option
Specifies one of the following display formats.
Option | Format
h | Hexadecimal
d | Decimal
t | Decimal
o | Octal
q | Octal
y | Binary

By default, the command displays all formats: decimal, hexadecimal, octal, binary, ASCII, and Boolean.

string
Formatting string. Can be a combination of text and zero or more of the following formatting descriptors and escape sequences.
String | Description
%% Displays a percent sign (%).
%A | Displays matching expr as an address.
%b | Displays matching expr in binary format.
%c | Displays matching expr as a character.
%d | Displays matching expr in decimal format.
%G | Evaluates matching expr as an address and displays the group and symbol associated with the address in group:symbol format.
%M | Evaluates matching expr as an address and displays the map file, group and symbol associated with the address in map:group:symbol format.
%o | Displays matching expr in octal format.
%S | Evaluates matching expr as an address and displays the map file, group and symbol associated with the address.
%s | Evaluates matching expr as an address and displays the string at that address.
%u | Displays matching expr in unsigned decimal format.
%X | Displays matching expr in hexadecimal format.
%x | Displays matching expr in hexadecimal format
\a | Inserts a bell (alert) character.
\b | Inserts a backspace character.
\n | Inserts a new line character.
\r | Inserts a carriage return character.
\t | Inserts a horizontal tab character.

One expression must be given for each formatting descriptor in the string. Multiple expressions can be separated with commas (,) or spaces.

Formatting descriptors can have the following optional prefixes.
Prefix | Description
A | [-][width][.precision][a][p][n][L][H][N]
b | [-][0][width][.precision][p][n]
d | [-][+][ ][0][width][.precision][p][n]
G | [-][width][.precision][a][p][n][L][H][N]
M | [-][width][.precision][a][p][n][L][H][N]
o | [-][0][width][.precision][p][n]
s | [-][width][.precision][a]
S | [-][width][.precision][a][p][n][L][H][N]
u | [-][0][width][.precision][p][n]
X | [-][#][0][width][.precision][p][n]
x | [-][#][0][width][.precision][p][n]

Specifying an asterisk (*) for the width or precision parameter causes the field width or precision, respectively, to be picked up from the next parameter. Decimal values can also be specified for the width and precision parameters. The prefix letters have the following meanings.
Prefix | Description
a | Address argument size
H | Display 16-bit offset
L | Display 32-bit offset
N | Display offset only
p | Get the previous symbol, symbol address, or offset
n | Get the next symbol, symbol address, or offset


.<dev_name> (Dot Device)

Directs the VMM to send a Debug_Query message to the given virtual device. If the virtual device supports a debugging interface, it displays information about its operating state.

.dev_name

Parameters

dev_name
Can be the name of any virtual device.

Remarks

Because virtual devices are not required to support the Debug_Query message, many do not produce debugging output. If a virtual device does generate output, it is typically device specific and not normally useful in a typical debugging situation.

Examine the sample virtual devices to determine how to use the Trace_Out macro, and the In_Debug_Chr service to generate useful debugging information.


.? (Help)

The .? command displays a list of external commands. These commands are part of debugger, but they are specific to the environment in which the debugger is running.

.?


.b (Baud Rate)

The .b command sets the baud rate for the debugging port (COM2).

.b number [addr]

Parameters

number
Specifies the baud rate. It can be one of the following values: 150, 300, 600, 1200, 2400, 4800, 9600, or 19200. Because the default radix for the debugger is 16, you must type t after the number to indicate a decimal value.
addr
Specifies 1 for COM1 or 2 for COM2; anything else is taken as a base port address. If there is no COM2, the debugger checks for COM1 and then for any other COM port address in the read-only memory (ROM) data area to use as the console.

Example

The following example sets the baud rate to 1200:

#.b 1200t


.df (Display Free Memory)

The .df command displays a list of the free global memory objects in the global heap.

.df

Remarks

The list has the following form:

address: size owner [chain]

address
Specifies physical and heap addresses.
size
Specifies the size of the object, in bytes.
owner
Always specifies that the module is free.
chain
Specifies the previous and next addresses in the list of least recently used (LRU) objects. The debugger displays the addresses only if the segment is movable and discardable.


.dg (Display Global Memory)

The .dg command displays a list of the global memory objects in the global heap. The command displays information in much the same way as the HEAPWALK application.

.dg [object]

Parameters

object
Specifies the first object to be listed. The object parameter can be a handle, a selector, or a heap address.

Remarks

The list has the following form:

address: size segment-type owner [handle flags chain]
address
Specifies physical and heap addresses.
size
Specifies the size of the object, in bytes.
segment-type
Specifies one of the following object types.
Type | Description
CODE | Segment contains application code.
DATA | Segment contains application data and possible stack and local heap data.
FREE | Segment belongs to pool of free memory objects ready for allocation by an application.
PRIV | Segment contains private data.
SENTINAL | Segment marks the beginning or end of the global heap.

owner
Specifies the module name of the application or library that allocated the memory object. The acronym PDB is used for memory objects that represent process descriptor blocks. These blocks contain execution information about applications.
handle
Specifies the handle of the global memory object. If the debugger displays no handle, the segment is fixed.
flags
Specifies one of the following values.
Value | Description
D | The segment is movable and discardable.
L | The segment is locked. If the segment is locked, the lock count appears to the right of the flag.

If the debugger displays a handle but no flag, the segment is movable but not discardable.

chain
Specifies the previous and next addresses in the list of least recently used (LRU) objects. Addresses are displayed only if the segment is movable and discardable (specified by the D flag).


.dh (Display Local Heap)

The .dh command displays a list of the local memory objects in the local heap (if any) belonging to the current data segment. The command uses the current value of the DS register to locate the data segment and check for a local heap.

.dh

Parameters

offset
Specifies the address offset from the beginning of the data segment to the local memory object.
size
Specifies the size of the object, in bytes.

Remarks

The list of memory objects has the following form:

offset: size { BUSY | FREE }

If BUSY is displayed, the object has been allocated and is currently in use. If FREE is displayed, the object is in the pool of free objects ready to be allocated by the application. A special memory object, SENTINAL, may also be displayed.


.dm (Display Modules)

The .dm command displays a list of the global modules in the global heap.

.dm

Parameters

module-handle
Specifies the handle of the module.
module-type
Specifies either a dynamic-link library (DLL) or the name of the application you are debugging.
module-name
Specifies the name of the module.
filename
Specifies the name of the file from which you loaded the application.

Remarks

The list has the following form:

module-handle module-type module-name filename


.dq (Display Task Queues)

The .dq command displays a list containing information about the various task queues supported by the system.

.dq

Parameters

task-descriptor-block
Specifies the selector or segment address.

The task descriptor block is identical to the process descriptor block (PDB).

stack-segment:stack-pointer
Specifies the stack segment and pointer.
number-of-events
Specifies the number of events waiting for the segment.
priority
Specifies the priority of the segment.
internal-messaging-information
Specifies information about internal messages.
module
Specifies the module name.

Remarks

The list has the following form:

task-descriptor-block stack-segment:stack-pointer number-of-eventspriority internal-messaging-information module


.ds (Dump Stack)

Dumps the protected-mode stack and displays near code-segment labels (if available) next to each doubleword value from the stack.

.ds

Remarks

One important distinction that should be made is the difference between the k and the .ds commands. The k command will walk the Windows stack as long as the debugger is stopped in Windows-based application or dynamic-link library (DLL) code. However, if the debugger is tracing through ring 0 code, the k command will not produce any useful output. For this reason, the .ds command has been provided to display the ring 0 stack.


.du (Display Least Recently Used)

The .du command displays a list of the least recently used (LRU) global memory objects in the global heap.

.du

Parameters

address
Specifies physical and heap addresses.
size
Specifies the size of the object, in bytes.
segment-type
Specifies one of the following object types.
Type | Description
CODE | Segment contains application code.
DATA | Segment contains application data and possible stack and local heap data.
FREE | Segment belongs to pool of free memory objects ready for allocation by an application.
PRIV | Segment contains private data.
SENTINAL | Segment marks the beginning or end of the global heap.

owner
Specifies the module name of the application or library that allocated the memory object. The acronym PDB is used for memory objects that represent process descriptor blocks. These blocks contain execution information about applications.
handle
Specifies the handle of the global memory object.
flags
Specifies D, which means the segment is movable and discardable.
chain
Specifies the previous and next addresses in the LRU list.

Remarks

The list has the following form:

address: size segment-type owner [handle flags chain]


.m (Memory)

Displays information about memory and memory objects.

.m[struct][link] [expression [L count]]

Parameters

struct
Specifies one of the following command options.
Option | Description
a | Display arena record.
C | Display context descriptor
d | Display page directory entry
e | Toggle stopping in the debugger for memory manager errors
f | With no arguments, dump page fault log. With arguments, set to log faults in a specific range (syntax: .MF <address> L<lengh in bytes>).
Fb | Toggle stopping for eached logged page fault.
Ff | Toggle logging page faults to debug terminal.
G | Display pager descriptor
h [handle] | Displays heap information for the given handle or global information if no handle is given.
Hs [handle] | Dump statistics about a given heap.
Hw | Toggle paranoid VMM32 heap checking.
Hx [handle] | Check for corruption on given heap defaults to VMM32 fixed heap.
I | Displays instanced data regions.
M [address [l page-count]] | Force memory present. The address defaults to last page faulted upon (contents of cr2 register)
n | Force all unlocked memory not present
r | Display arena header
s | Dump memory manager statistics
t | Displays page table entry
u | Toggles computing checksums for page-outs and page-ins
w | Dumps allocators of all committed pages.
X | Displays all memory structures for an address.
Y | Displays valid physical memory ranges.

If no letter is given, the command displays all the structures associated with a given linear address.

link
Direction to walk structures if dumping more than one. Can be b to walk backward or f to walk forward. If link is not given, the default is to walk adjacent entries.
expression
An expression identifying the structure to display. Can be a linear address, handle, array index, or other value as specified by the struct parameter.
count
Number of structures to display if the specified structures are linked.

Remarks

The default address for the .m and .mx commands is the contents of the cr2 register (the last page fault) and for the other commands it is the first structure in the list. For example, .m displays information about the page that most recently faulted.

A word of caution about the .mm, .mhx, and .mhs commands. If you invoke these commands at the wrong time, you can crash your system. The only time it can be guaranteed safe is if you are currently executing ring 3 code. At other times we may be in the middle of another file system or memory manager operation.


.reboot (System Restart)

The .reboot command restarts the target system.

.reboot


.v (Virtual Machine Commands)

Displays information about the current virtual machine (VM).

.v[option]

Parameters

option
Specifies one of the following command options.
Option | Description
c | Displays the standard fields of the current VM's control block.
H | Displays the current VM's handle.
m | Displays the status of the current VM. Status information includes re-entry count, VM handle, critical section state, client registers, and top entries from the client's stack.
R | Displays the current VM's client registers if the 80386 debugger is running in protected mode.
s | Displays the current VM's virtual mode stack if the debugger is running in protected mode.
l | Displays a list of all valid VM handles.


.vmm (Display VMM Commands)

Displays a menu of subcommands. Pressing a single key causes the corresponding command to be carried out.

.vmm


.w (Display Win32 Object)

The .w command displays information about a Win32 object.

.w[option][expression]

Parameters

option
Specifies one of the following options.
Option | Description
HE | Toggles stopping in debugger for Win32 memory manager error returns
HW | Toggles Win32 paranoid heap corruption checking
L | Displays LDT-related information, for example, selman lists, sel free lists.
M | Displays module table.
MP [ppdb] | Displays module table for process. If ppdb is omitted, the module table for the current process is displayed.
P [ppdb] | Displays process list.
C context | Displays context record.
E exception | Displays exception record.
D dispatcherContext | Displays dispatcher context.
S | Displays the status of all ring 3 system critical sections.
T [ppdb] | Displays the process handle table. If ppdb is omitted, the handle table for the current process is displayed.

expression
Address of a Win32 object of one of the following types: thread, process, semaphore, event, mutex, or critical section. If expression is omitted, information on all threads is displayed.

Remarks

If any data item being dumped resides in not-present memory, the address of that data item is displayed in brackets.


bc (Breakpoint Clear)

The bc command removes one or more defined breakpoints.

bc list | *

Parameters

list
Specifies any combination of integer values in the range 0 through 9. If you specify list, the debugger removes the specified breakpoints.
*
Clears all breakpoints.

Example

The following example removes breakpoint 0, 4, and 8:

bc 0 4 8


bd (Breakpoint Disable)

The bd command temporarily disables one or more breakpoints. To restore breakpoints disabled by the bd command, use the be command.

bd list | *

Parameters

list
Specifies any combination of integer values in the range 0 through 9. If you specify list, the debugger disables the specified breakpoints.
*
Disables all breakpoints.

Example

The following example disables breakpoints 0, 4, and 8:

bd 0 4 8


be (Breakpoint Enable)

The be command restores (enables) one or more breakpoints that have been temporarily disabled by a bd command.

be list | *

Parameters

list
Specifies any combination of integer values in the range 0 through 9. If you specify list, the debugger enables the specified breakpoints.
*
Enables all breakpoints.

Example

The following example enables breakpoints 0, 4, and 8:

be 0 4 8


bl (Breakpoint List)

The bl command lists current information about all breakpoints created by the bp command.

bl

Remarks

For each existing breakpoint, the command displays the breakpoint number, the enabled status ('e' for enabled, 'd' for disabled, 'I' for invalid), the breakpoint address, the number of passes remaining (if any), the initial number of passes in parentheses (if any), and debugger commands to be executed when the breakpoint is reached (if any).

Example

The following example shows a typical list:

0 d  %004010b5 [_MyTest] 4 (10) "db ds:edi"1 eI %0040110f [_MyWndProc@16 + 5a]


bp (Breakpoint)

The bp command creates a software breakpoint at an address. When the application is running, software breakpoints stop execution and force the debugger to execute the default or optional command string.

bp[number]addr [count] ["cmds"]

Parameters

number
Specifies which breakpoint is being created. No space is allowed between the bp and number. If number is omitted, the first available breakpoint number is used. The debugger allows up to 10 software breakpoints (0 through 9). If you specify more than 10 breakpoints, the debugger returns the message: "Too Many Breakpoints."
addr
Specifies any valid instruction address — the first byte of an operation code (opcode). The addr parameter is required for all new breakpoints.
count
Specifies the number of times the breakpoint is to be ignored before being executed. It can be any 16-bit value.
cmds
Specifies an optional list of debugger commands to be executed in place of the default command when the breakpoint is reached. You must enclose optional commands in quotation marks and separate optional commands with semicolons (;).

Remarks

Unlike breakpoints created by the g command, software breakpoints remain in memory until you remove them with the bc command or temporarily disable them with the bd command.

Example

The following example creates a breakpoint at address CS:401000:

bp 401000

The following example creates breakpoint 8 at address given by the symbol _MyTest. When the breakpoint occurs, the debugger displays bytes at DS:SI:

bp8 _MyTest "db DS:SI"


br (Breakpoint Register)

The br command sets an debug register breakpoint. Debug registers can be used to break on data reads and writes and instruction execution. Up to four debug registers can be set and enabled at one time.

br[number] flags [count] ["cmds"]

Parameters

number
Specifies which breakpoint is being created. No space is allowed between the br command and the number parameter. If number is omitted, the first available breakpoint number is used.
flags
Specifies the length and break conditions for the breakpoint. This parameter can be some combination of the following values:
Value | Description
1 | Set 1-byte length (default value).
2 | Set word length on word boundary.
4 | Set doubleword length on doubleword boundary.
E | Break on instruction execution only (1-byte length only).
W | Break on writes only.
R | Break on reads and writes.

count
Specifies the number of times the breakpoint is to be ignored before being executed. It can be any 16-bit value.
cmds
Specifies an optional list of debugger commands to be executed in place of the default command when the breakpoint is reached. You must enclose the group of optional commands in quotation marks and separate optional commands with semicolons (;).


c (Compare)

The c command compares one memory location with another memory location.

c range addr

Parameters

range
Specifies the block of memory that is to be compared with a block of memory starting at addr.
addr
Specifies the starting address of the second block of memory.

Remarks

If the two memory areas are identical, the debugger displays nothing and returns the debugger prompt. Differences, when they exist, are displayed in this form: addr1 byte1 byte2 addr2.

Example

The following example compares the bytes at addresses in the range 100h to 1FFh with the corresponding bytes at address from 300h to 3FFh:

c100 1FF 300

The following example compares the same block of memory as the previous example but specifies the range by using the L (length) option.

c100 L 100 300


d (Display)

The d command displays the contents of memory at a given address or in a range of addresses. The d command displays one or more lines, depending on the range given.

d [range]

Parameters

range
Specifies the block of memory to display. If you omit range, the d command displays the next byte of memory after the last one displayed. The d command must be separated by at least one space from any range value.

Remarks

Each line displays the address of the first item displayed. The command always displays at least one value. The memory display is in the format defined by a previously executed da, db, dd, or dw command. Each subsequent d (typed without parameters) displays the bytes immediately following those last displayed.


da (Display ASCII)

The da command displays as ASCII characters the values of the bytes at a given address or in a given range. The display includes all bytes up to the first zero byte. Nonprinting characters and characters having values greater than 127 are denoted by a period (.).

da [range]

Parameters

range
Specifies the block of memory to display. If you omit range, 128 bytes are displayed beginning at the first address after the address displayed by the previous da command.


db (Display Bytes)

The db command displays the values of the bytes at a given address or in a given range.

db [range]

Parameters

range
Specifies the block of memory to display. If you omit range, 128 bytes are displayed beginning at the first address after the address displayed by the previous db command.

Remarks

The display is in two portions: a hexadecimal display (each byte is shown in hexadecimal format) and an ASCII display (the bytes are shown as ASCII characters). A nonprinting character is denoted by a period (.) in the ASCII portion of the display. Each display line shows 16 bytes, with a hyphen between the eighth and ninth bytes. Each displayed line begins on a 16-byte boundary.

Example

The following example displays 0Ah bytes of memory, beginning at the specified address:

db CS:100 0A

The following example displays lines in a format similar to the following:

04BA:00000100 54 4F 4D 20 53  . . . 45 52 TOM SAWYER

Each line of the display begins with an address, incremented by 10h from the address on the previous line.


dd (Display Doublewords)

The dd command displays the hexadecimal values of the doublewords at the address specified or in the specified range of addresses. The dd command displays one or more lines, depending on the range given.

dd [range]

Remarks

Each line displays the address of the first doubleword in the line, followed by up to four hexadecimal doubleword values. The hexadecimal values are separated by spaces. The dd command displays values up to the end of the range or until the first 32 doublewords have been displayed.

Parameters

range
Specifies the block of memory to display. If you omit range, 32 doubleword values are displayed beginning at the first address after the address displayed by the previous dd command.

Example

The following example displays the doubleword values from CS:100 to CS:110:

dd CS:100 110
04BA:0100 7473:2041 676E:6972 5405:0104 0A0D:7865
04BA:0110 0000:002E

No more than four values per line are displayed.


dg (Display GDT)

The dg command displays the specified range of entries in the global descriptor table (GDT).

dg[a] [range]

Parameters

a
Displays all entries in the table, not just the valid ones. By default, only the valid GDT entries are displayed. If range specifies a local descriptor table (LDT) selector, the command displays the appropriate LDT entry.
range
Specifies the range of entries to be displayed. If you omit range, the entire table is displayed.

Remarks

The command displays the selector, descriptor type, base address, limit, privilege, and other descriptor flags.


di (Display IDT)

The di command displays the specified range of entries in the interrupt descriptor table (IDT).

di[a] [range]

Parameters

a
Displays all entries in the table, not just the valid ones.
range
Specifies the range of entries to be displayed. If you omit range, the entire table is displayed.

Remarks

The command displays the interrupt number, the interrupt type, the interrupt address, privilege, and descriptor flags.


dl (Display LDT)

The dl command displays the specified range of entries in the local descriptor table (LDT).

dl[a | p | s | h] [range]

Parameters

a
Displays all entries in the table, not just the valid ones. By default, only the valid LDT entries are displayed. If range specifies a global descriptor table (GDT) selector, it displays the appropriate GDT entry.
p
Displays private segment selectors.
s
Displays shared segment selectors.
h
Displays huge segment selectors. To display the huge segment selectors, give the shadow selector followed by the maximum number of selectors reserved for that segment plus 1.
range
Specifies the range of entries to be displayed. If you omit range, the entire table is displayed.

Remarks

The command displays the selector, descriptor type, base address, limit, privilege, and other descriptor flags.


dp (Display Page Directory and Tables)

The dp command displays the page directory and page tables. Page tables are always skipped if the corresponding page directory entry is not present. Page directory entries appear with an asterisk next to the page frame.

dp[a|d] [range]

Parameters

a
Displays all present page directory and page table entries; by default, page directory and page table entries that are zero are skipped.
d
Displays only page directory entries. If a count is given as part of the optional range, it will be interpreted as a page directory entry count.
range
Specifies the range of linear addresses for page tables.

Remarks

The command displays the entry address, frame, and entry flags. Page directory entries are marked with an asterisk (*). Entry flags have the following meanings.

Flag | Description
A | Accessed
c | clean
CD | Cache Disable
D | Dirty
n | Not-present
P | Present
r | Read-only
s | Supervisor
U | User
u | Unaccessed
W | Writable
WT | Write Through


dt (Display Task State Segment)

The dt command displays the current task state segment (TSS) or the selected TSS if you specify the optional address.

dt [addr]

Parameters

addr
Specifies the address of the TSS to display. If no addr is given, dt displays the current TSS pointed to by the TR register.


dw (Display Words)

The dw command displays the hexadecimal values of the words at a given address or in a given range of addresses.

dw [range]

Parameters

range
Specifies the range of addresses to display. If you omit range, 64 words are displayed beginning at the first address after the address displayed by the previous dw command.

Remarks

The command displays one or more lines, depending on the range given. Each line displays the address of the first word in the line, followed by up to eight hexadecimal word values. The hexadecimal values are separated by spaces. The command displays values until the end of the range or until the first 64 words have been displayed.

Example

The following example displays the word values from CS:100 to CS:110:

dw CS:100 110
04BA:0100 2041 7473 6972 676E 0104 5404 7865 0A0D
04BA:0110 002E


dx (Display Loadall Buffer)

The dx command displays the contents of the loadall buffer.

dx


e (Enter)

The e command enters byte values into memory at a specified address. You can specify the new values on the command line or let the debugger prompt you for values.

e addr [list]

Parameters

addr
Specifies the address of the first byte to be entered.
list
Specifies the byte values used for replacement. These values are inserted automatically. If an error occurs when you are using the list form of the command, no byte values are changed.

Remarks

If the debugger prompts you, it displays the address and its contents and then waits for you to perform one of the following actions:

  • Replace a byte value with a value you type. Type the value after the current value. If the byte you type is an invalid hexadecimal value or contains more than two digits, the system does not echo the illegal or extra character.
  • Press the SPACEBAR to advance to the next byte. To change the value, type the new value after the current value. If, when you press the SPACEBAR, you move beyond an 8-byte boundary, the debugger starts a new display line with the address displayed at the beginning.
  • Type a hyphen (-) to return to the preceding byte. If you decide to change a byte before the current position, typing the hyphen returns the current position to the previous byte. When you type the hyphen, a new line is started with its address and byte value displayed.
  • Press ENTER to terminate the e command. You can press ENTER at any byte position.

Example

The following example prompts you to change the value EB at CS:100:

eCS:100
04BA:0100 EB.

To step through the subsequent bytes without changing values, press the SPACEBAR. In the following example, the SPACEBAR is pressed three times:

04BA:0100 EB.41  10. 00. BC.

To return to a value at a previous address, type a hyphen, as shown in the following example:

04BA:0100  EB.41    10. 00. BC.-
04BA:0102  00.-
04BA:0101  10.

This example returns to the address CS:101.


f (Fill)

The f command fills the addresses in a specified range with the values in the specified list.

f range list

Parameters

range
Specifies the block of memory to be filled. If range contains more bytes than the number of values in list, the debugger uses list repeatedly until all bytes in range are filled. If any of the memory in range is not valid (bad or nonexistent), an error occurs in all succeeding locations.
list
Specifies the list of values to fill the given range. If list contains more values than the number of bytes in range, the debugger ignores the extra values in list.

Example

The following example fills memory locations 04BA:100 through 04BA:1FF with the bytes specified, repeating the five values until it has filled all 100h bytes:

f04BA:100 L 100 42 45 52 54 41


g (Go)

The g command executes the application currently in memory. If you type the g command by itself, the current application runs as if it had been run outside the debugger. If you specify =addr, execution begins at the specified address.

g[s|h|t|z] [=addr [addr[...]] ]

Parameters

s
Shows the time, in microseconds, from when the system is started with gs until the next entry to the debugger. No attempt is made to calculate and remove debugger overhead from the measurement. Requires a timing card.
h
Displays the approximate debugger overhead in the s option. Requires a timing card.
t or z
Allows trapped exceptions to resume at the original trap handler address without having to unhook the exception. Use these options instead of the vcp d; t; vsp d command.
=addr
Specifies the address at which execution is to begin. The equal sign (=) is needed to distinguish the starting address from the breakpoint address.
addr
Specifies one or more breakpoint addresses where execution is to halt. You can specify up to 10 breakpoints, but only at addresses containing the first byte of an operation code (opcode). If you attempt to set more than 10 breakpoints, an error message is displayed.

Remarks

Specifying an optional breakpoint address causes execution to halt at the first address encountered, regardless of the position of the address in the list of addresses that halts execution or application branching. When execution of the application reaches a breakpoint, the default command string is executed.

The stack (SS:SP) must be valid and have 6 bytes available for this command. The g command uses an iret instruction to cause a jump to the application being tested. The stack is set, and the user flags, CS register, and IP register are pushed on the user stack. (If the user stack is not valid or is too small, the operating system may crash.) An interrupt code (0CCh) is placed at the specified breakpoint addresses.

When the debugger encounters an instruction with the breakpoint code, it restores all breakpoint addresses listed with the g command to their original instructions. If you do not halt execution at one of the breakpoints, the interrupt codes are not replaced with the original instructions.

Example

The following example executes the application currently in memory until address 7550 in the CS selector is executed. The debugger then executes the default command string, removes the int 3 trap from this address, and restores the original instruction. When you resume execution, the original instruction is executed.

gCS:7550


h (Hex)

The h command performs hexadecimal arithmetic on the two specified parameters.

h word1 word2

Parameters

word1
Specifies a 16-bit word parameter.
word2
Specifies a 16-bit word parameter.

Remarks

The debugger adds, subtracts, and multiplies the two parameters; divides the second parameter by the first; and then displays the results on one line. The debugger does 32-bit multiplication and displays the result as doublewords. The debugger displays the result of division as a 16-bit quotient and a 16-bit remainder.


i (Input)

The i command accepts and displays 1 byte from a specified port.

i word

Parameters

word
Specifies the 16-bit port address.

Example

The following example displays the byte at port address 2F8h:

i2F8


j (Conditional)

The j command executes selected commands based on whether the specified expression is TRUE or FALSE. The j command is useful in breakpoint commands to conditionally break execution when an expression becomes TRUE.

j expr [cmds-if-true][;cmds-if-false]

Parameters

expr
Evaluates to a Boolean TRUE or FALSE.
cmds-if-true
Specifies a list of debugger commands to be executed when expr is TRUE. More than one command can be given, but the commands must be separated by semicolons and the complete list must be enclosed in single or double quotation marks.
cmds-if-false
Specifies a list of debugger commands to be executed when expr is FALSE. The preceding semicolon is required. More than one command can be given, but the commands must be separated by semicolons and the complete list must be enclosed in single or double quotation marks.

Example

The following example causes execution to continue if EAX equals zero when the breakpoint is reached:

bp 167:1454 "J EAX == 0 G"

The following example displays the registers and continues execution when the byte pointed to by DS:SI +3 is equal to 40h; otherwise, it displays the descriptor table:

bp 167:1462 "J BY (DS:SI+3) == 40 'R;G';DG DS"


k (Stack Trace)

The k command displays the current stack frame. Each line shows the name of a procedure, its arguments, and the address of the statement that called it. The command displays four 2-byte arguments by default. The ka command changes the number of arguments displayed by this command.

k[b|s|v] [addr] [addr]

Parameters

b
Indicates the stack frame is 32 bits wide.
s
Indicates the stack frame is 16 bits wide.
v
Displays the verbose version of stack information — that is, information about stack location and frame pointer values for each frame.
addr
Specifies an optional stack-frame address (SS:EBP) or an optional code address (CS:EIP).

Remarks

Using the k command at the beginning of a function (before the function prolog has been executed) gives incorrect results. The command uses the BP register to compute the current backtrace, and this register is not correctly set for a function until its prolog has been executed.


ka (Stack Trace Arguments)

The ka command sets the number of arguments displayed for all subsequent stack trace commands. The initial default value is 4.

ka count

Parameters

count
Specifies the number of arguments to be displayed. The count parameter must be in the range 0 through 1Fh.


kt (Stack Trace for Task)

The kt command displays the stack frame of the current task or the task specified by the addr parameter. Each line shows the name of a procedure, its arguments, and the address of the statement that called it. The command displays four 2-byte arguments by default. The ka command changes the number of arguments displayed by this command.

k[b|s|v]t [addr]

Parameters

b
Indicates the stack frame is 32 bits wide.
s
Indicates the stack frame is 16 bits wide.
v
Displays the verbose version of stack information — that is, information about stack location and frame pointer values for each frame.
addr
Specifies the segment address of the process descriptor block (PDB) for the task to be traced. To obtain the addr value, use the .dq (Dump Task Queue) command. If addr is not supplied, the kt command displays the stack frame of the current task.


la (List Absolute Symbols)

The la command lists the absolute symbols in the active map.

la


lg (List Groups)

The lg command lists the address and the name of each group in the active map.

lg


lm (List Maps)

The lm command lists the symbol files currently loaded and indicates which one is active. The last symbol file loaded is made active by default. Use the w command to change the active file.

lm


ln (List Nearest Symbol)

The ln command lists the symbol nearest the specified address.

ln [addr]

Parameters

addr
Specifies any valid instruction address. The default value is the current disassembly address.

Remarks

The command lists the nearest symbol before and after the specified addr parameter. This command also shows line-number information if it is available in the symbol file.

The ln command without the addr parameter displays the nearest symbols before and after the current disassembly address.


ls (List Symbols)

The ls command lists the symbols in the specified group or lists names that match the search specification in all groups. The only valid wildcard is a single asterisk (*) as the last character on the command line; all other characters are ignored.

ls group-name | name-chars | *

Parameters

group-name
Names the group that contains the symbols you want to list.
name-chars
Specifies the beginning characters of the symbols you want to list.


lse (List Symbols by Regular Expression)

The lse command lists the symbols specified by the given regular expression.

lse regular-expression

Parameters

regular-expression
Specifies a regular expression.


m (Move)

The m command moves a block of memory from one memory location to another. If part of the destination block overlaps some of the source block, the move is always performed without loss of data. Addresses that could be overwritten are moved first.

m range addr

Parameters

range
Specifies the block of memory to be moved.
addr
Specifies the starting address at which the memory is to be relocated.

Remarks

For moves from higher to lower addresses, the sequence of events is first to move the data at the block's lowest address and then to work toward the highest. For moves from lower to higher addresses, the sequence is first to move the data at the block's highest address and then to work toward the lowest.

Example

The following example first moves the data at address CS:110 to CS:510 and then moves the data at CS:10F to CS:50F, and so on, until the data at CS:100 is moved to CS:500:

mCS:100 110 CS:500


o (Output)

The o command writes a byte to a 16-bit port address.

o word byte

Parameters

word
Specifies the 16-bit port address to be written to.
byte
Specifies the 8-bit value to be written to the port.

Example

The following example writes the byte value 4Fh to output port 2F8h:

2F8 4F


p (Program Trace)

The p command executes the instruction at a specified address and displays the current values of all the registers and flags (whatever the zd command has been set to). It then executes the default command string, if any.

p[n|t|z] [=addr][count]

Remarks

The p command is identical to the t command, except that it automatically executes and returns from any calls or software interrupts it encounters. The t command always stops after executing into the call or interrupt, leaving execution control inside the called routine.

Parameters

n
Suppresses the register display so just the assembly line is displayed. The suppression results only if the default command, zd, is set to a normal setting, r.
t or z
Allows trapped exceptions to resume at the original trap handler address without having to unhook the exception.
addr
Specifies the starting address at which to begin execution. If you omit the optional addr parameter, execution begins at the instruction pointed to by the CS and IP registers. Use the equal sign (=) only if you specify addr.
count
Specifies the number of instructions to execute before stopping and executing the default command string. The command executes the default command string for each instruction before executing the next.

Example

The following example executes the instruction pointed to by the current CS and IP register values before it executes the default command string:

p

The following example executes the instruction at address CS:120 before it executes the default command string:

p=120


r (Register)

The r command displays the contents of one or more central processing unit (CPU) registers and allows the contents to be changed to new values. If you specify the reg parameter with the r command, the command displays the value of that register in hexadecimal format and prompts for a new value. If you specify a reg and a value, the command sets the register to the given value.

r[t][reg[=value]]

Parameters

t
Displays registers in terse format.
reg
Specifies the register to be displayed. If you specify f or msw for reg, the debugger displays the flags in a row at the beginning of a new line and prompts for one or more flag values. If you omit reg, the debugger displays the contents of all registers and flags along with the next executable instruction.
value
Specifies the new value for the register. This parameter can be a number or a combination of the following values.
Value | Description
OV | Overflow set
NV | Overflow clear
DN | Direction decrement
UP | Direction increment
EI | Interrupt enabled
DI | Interrupt disabled
NG | Sign negative
PL | Sign positive
ZR | Zero set
NZ | Zero clear
AC | Auxiliary carry set
NA | Auxiliary carry clear
PE | Parity even
PO | Parity odd
CY | Carry set
NC | Carry clear
NT | Nested task switch (on and off)
TS | Sets the task switch bit. (MSW only)
EM | Sets the emulation processor extension bit. (MSW only)
MP | Sets the monitor processor extension bit. (MSW only)
PM | Sets the protected-mode bit. (MSW only)

Flag values can be in any order. You do not have to leave spaces between these values.

Remarks

If you type more than one value for a flag or enter an invalid flag name, the flags up to the error in the list are changed and those flags at and after the error are not changed. In addition, the debugger display the message: "Bad Flag."

Setting the protected-mode bit from within the debugger does not set the target system to run in protected mode. The debugger simulates the setting. To configure the target system to run in protected mode, you would have to set the PM bit in the MSW register and reset the target system to restart in protected mode.


s (Search)

The s command searches an address range for a specified list of bytes or an ASCII character string.

s range list | "string"

Parameters

range
Specifies the block of memory to be searched.
list
Specifies one or more byte values to search for.
string
Specifies an ASCII character string to be searched for. The string must be enclosed in quotation marks.

Remarks

You can include one or more bytes in list, but multiple bytes must be separated by a space or comma. When you search for more than one byte, the command returns the address of only the first byte in the string. When list contains only one byte, the debugger displays the addresses of all occurrences of the byte in range.

Example

The following example searches for byte 41h in the address range CS:100 to CS:110:

sCS:100 110 41
04BA:0104
04BA:010D


t (Trace)

The t command executes one or more instructions along with the default command string and then displays the decoded instruction. If you include the start_addr parameter, tracing starts at the specified address. Otherwise, the command steps through the next machine instruction and then executes the default command string. The t command uses the hardware trace mode of the Intel microprocessor. Consequently, you can also trace instructions stored in read-only memory (ROM).

t[a|c|n|s|x|z][=start_addr][count][addr]

Parameters

a
Indicates that an ending address is specified for the trace. Instructions are traced until the address in addr is reached.
c
Suppresses all output and counts instructions traced. An ending address is required for this command. Instructions are traced until the address in addr is reached.
n
Suppresses the register display so just the assembly line is displayed. This works only if the default command, zd, is set to r (the normal setting).
s
Suppresses output; the instruction and count are displayed for each call and the return from that call.
x
Forces the debugger to trace regions of code known to be untraceable (_PGSwitchContext, for example).
z
Allows original trap handler address to be traced into without having to unhook the exception. Use this option instead of vcp d; t; vsp d.
start_addr
Specifies the instruction address at which to start tracing. The equal sign (=) is required.
count
Specifies the number of instructions to execute and trace.
addr
Specifies the instruction address at which to stop tracing.

Remarks

The debugger executes and displays the results of the default command string for each instruction. The display is scrolled until the last instruction is executed. Press the CTRL+S key combination to stop the scrolling and CTRL+Q to resume.

Example

The following command causes the debugger to execute 16 (10h) instructions beginning at 011A in the current selector:

t=011A 10


u (Disassemble)

The u command disassembles bytes and displays the source statements, with addresses and byte values, that correspond to them.

u [range]

Parameters

range
Specifies the block of memory in which instructions are to be disassembled. If no range is given, the command disassembles the next 20h bytes.

Remarks

The display of disassembled code looks similar to a code listing for an assembled file. If you type the u command by itself, 20h bytes are disassembled at the first address after the one displayed by the previous u command.


v (Version Number)

The v command displays the current debugger version number and date.

v


vc (Vector Clear)

The vc command clears the specified interrupt vector and reinstalls the previous interrupt vector.

vc[n | p | r | v] number[,number [,...]]

Parameters

n
Removes the beep from traps that beep when encountered; does not clear the traps.
p
Clears protected-mode vectors only.
r
Clears real-mode vectors only.
v
Clears virtual 8086 (V86) mode vectors only.
number
Specifies the interrupt vector to clear.


vl (Vector List)

Lists the interrupt vectors that the debugger intercepts. Vectors that have been set with the vt command (as opposed to vs) are listed with an asterisk (*) following the vector number.

vl[n | p | r | v]

Parameters

n
Lists the traps that beep when encountered.
p
Lists the protected-mode vectors only.
r
Lists the real-mode vectors only.
v
Lists the virtual 8086 (V86) mode vectors only.


vo (Vector List New)

The vo command lists interrupt vectors in the display format based on the newvec option. For details, see the y command.

vo[n | p | r | v]

Parameters

n
Lists the traps that beep when encountered.
p
Lists the protected-mode vectors only.
r
Lists the real-mode vectors only.
v
Lists the virtual 8086 (V86) mode vectors only.


vs (Vector Trap Non-Supervisor)

The vs command adds a new interrupt vector to the list of intercepted vectors. Vectors set by this command do not intercept interrupts that occur at ring 0.

vs[n | p | r | v] number[,number[,...]]

Parameters

n
Beep when trap encountered.
p
Set trap for protected-mode vectors only.
r
Set trap for real-mode vectors only.
v
Set trap for virtual 8086 (V86) mode vectors only.
number
Specifies the interrupt vector to intercept.


vt (Vector Trap)

The vt command adds a new interrupt vector to the list of intercepted vectors.

vt[n | p | r | v] number[,number[,...]]

Parameters

n
Beep when trap encountered.
p
Set trap for protected-mode vectors only.
r
Set trap for real-mode vectors only.
v
Set trap for virtual 8086 (V86) mode vectors only.
number
Specifies the interrupt vector to intercept.


w (Change Map)

The w command changes the active map file.

w [map-name]

Parameters

map-name
Specifies the name of the map file you want to make active. Use the lm command to display a list of available map files.

Remarks

If map-name is not specified, the loaded maps are displayed and the user is prompted to select a map by pressing its corresponding number.


wa (Activate Map)

The wa command adds the specified map to the list of active maps.

wa map-name

Parameters

map-name
Specifies the map to add to the list of active maps.


wr (Deactivate Map)

The wr command removes the specified map from the list of active maps.

wr map-name

Parameters

map-name
Specifies the map to remove from the list of active maps.


x (Dump Debug Report)

Dumps a listing of the current execution environment.

x


y (Debugger Options)

The y command changes the debugger configuration. The following list describes the available configuration options. All settings are toggles.

y[? | option]

Parameters

?
Displays a list of supported options.

Following are the available configuration options:

/a
Controls automatic symbol loading. If this option is set, Windows will not load symbols automatically.
/n
Sets the following options:

codebytes
dislwr
int3line
newprompt
newreg
newvec
symaddrs

/v
Controls segment load notification messages. If this option is set, all segment load notifications will be displayed.
386env
Controls the size of addresses, registers, and so on when displayed. When this option is on, addresses, registers, and so on are shown in 32-bit format; otherwise, they are shown in 16-bit format.
codebytes
Causes code bytes to be displayed along with disassembled instructions.
disaddr
Causes addresses to be displayed with disassembled instructions.
disline
Causes filenames and line numbers to be displayed with disassembled instructions.
dislwr
Causes register and instruction names to be displayed in lowercase letters.
int3line
Causes the filename and line number to be displayed with int 3 instructions.
newprompt
Causes a double prompt when paging is enabled and a nesting level if the debugger is reentered.
newreg
Controls the format of the register display.
newvec
Controls the display format for the intercepted interrupt vectors.
regterse
Controls the number of registers displayed by the r command. When regterse is on, only the first three lines are displayed (instead of the normal six lines plus disassembly line).
scrncols
Sets the number of screen columns in the debug display. The default is 79 columns.
scrnlines
Sets the number of screen lines in the debug display. The default is 24 lines.
skipint3s
Causes the debugger to ignore inline int 3 instructions.
symaddrs
Causes symbol values to be displayed with the symbols.
teftibase
Sets the base port address for the timing card.


z (Zap)

Replaces the instruction bytes of the current int 3 instruction or the previous int 1 instruction with nop instructions. This allows the user to avoid int 1 or int 3 instructions that were assembled into the executable file by breaking into the debugger more than once.

z


zd (Execute Default)

The zd command executes the default command string. The default command string is executed every time a breakpoint is encountered during execution of the application or whenever a p or t command is executed.

zd

Remarks

The default command string is initially set to the r command by the debugger.

Use the zl command to display the default command string and the zs command to change the default command string.


zl (Display Default)

The zl command displays the default command string.

zl


zs (Set Default)

The zs command makes it possible for you to change the default command string.

zs "string"

Parameters

string
Specifies the new default command string. The string must be enclosed in single or double quotation marks. You must separate the debugger commands within the string with semicolons.

Example

The following example changes the current default command string to an r command followed by a c command:

zs "r;c100 L 100 300"

The following example begins execution whenever an int 3 instruction is executed in your test application. This example executes a g command every time an int 3 instruction is executed.

zs "j (by cs:ip) == cc 'g'"

You can use zs as follows to set up a watchpoint:

zs "j (wo 40:1234) == 0eeed;t"

This command traces until the word at 40:1234 is not equal to 0EEED. This does not work if you are tracing through the mode switching code in MS-DOS or other sections of code that cannot be traced.


AVI Editor

Windows 95/98

The AVI Editor (AVIEDIT.EXE) enables you to edit audio-video interleaved (AVI) files. An AVI file can contain several different types of data, such as video sequences, and multiple soundtracks. You can easily access these components with the AVI Editor.

The AVI Editor includes the following menu commands:

Menu | Commands
File | Open Close Merge Save As Save Options Exit
Edit | Cut Copy Paste Delete Name Info
Play | Play Preview Stop
Zoom | /4 /2 x1 x2 x4
Help | About


Capture Screen

Windows 95/98

The Capture Screen tool (CAPSCRN.EXE) enables you to capture video sequences and images from your computer screen. Capture Screen compresses video during capture, storing the sequence using run-length encoding. Capture Screen stores only those portions of the image that change from frame to frame.

The following table describes some of the commands contained on the Capture Screen menus:

Command | Description
Set Capture File | Enables you to choose the capture file.
Save Single Frame | Saves a single frame.
Play Captured Video | Plays the captured video.
Set Capture Window | Sets the screen area to capture.
Preferences | Sets options for video capture and Capture Screen.
Capture | Starts capturing video from the capture area. Press ESC to end video capture.


DrawDib Test

Windows 95/98

The DrawDib Test utility (DDTEST.EXE or DDETEST32) enables you to test the features provided by the DrawDib functions on any bitmap file.

DrawDib Test includes the following menu commands:

Menu | Commands
File | Open Close About Exit Test 4 bpp Test 8 bpp Test 16 bpp Test 24 bpp Test 32 bpp
Edit | Copy Paste
Compressor | Microsoft RLE Microsoft Video1 Intel Indeo Video R3.2 Cinepak Codec by Radius Compress It Info Configure About Quality
Options | Stretch 1:1 Stretch 2:3 Stretch 1:2 Stretch to Window Random Source Random Dest Random Src/Dst Just Draw It Background Halftone Buffer
Test | DrawDib time DrawDib test Display test Display test (160x120) [DDTEST only] Display test (320x240) [DDTEST only] Display test (80x60) [DDTEST only] Escape test Bitmap test [DDTEST only] DVA test [DDTEST only] Compress test Decompress test DecompressEx test Draw test


IDF Editor

Windows 95/98

The IDF Editor (IDFEDIT.EXE) enables you to edit instrument definition files (IDF). Use the following steps to edit an existing .IDF file.

To edit an .IDF file

  1. Click Open on the File menu. The instruments are displayed in the left pane, and the associated definition data is displayed in the right pane.
  2. Click any definition data that you wish to change and type in new values.
  3. To add new instruments, click New Instrument on the File menu.


RIFF Add

Windows 95/98

The RIFF Add tool (RIFFADD.EXE) enables you to add text or bitmaps to resource interchange file format (RIFF) files. You can use RIFF Add in either batch mode or interactive mode. In batch mode, RIFF Add takes additions from a script file. In interactive mode, you enter additions through the user interface.

You can add text into DISP and INFO chunks, and bitmaps into DISP chunks. RIFFADD can handle text with extended characters or DBCS characters. It supports a maximum length of 512 bytes. When you type text in the edit field, press CTRL+ENTER to enter a line break. When you type text in the script, use \r\n to enter a line break.

The following is the command-line syntax for RIFFADD:

riffadd [/b script] infile outfile
/b script
Specifies batch mode operation and a script file. The format for the script file is provided in the following Batch Mode section. You must specify the script file using an absolute path, unless it is in the Windows directory.
infile
Specifies the filename for the input file, using a relative or an absolute path.
outfile
Specifies the filename for the output file, using a relative or an absolute path.

Batch Mode

In batch mode, RIFF Add takes additions from a script file. The following is the format of the script file:

[RIFFADD]
ChunkType=STRING, "text"
ChunkType=FILE, file

The following is a sample script file:

[RIFFADD]
ISBJ=STRING, "This is the subject."
DISP_TEXT=FILE, e:\riffadd\files\file1.txt
ITCH=STRING, "This is the technician."
ICMT=STRING, "This is one line\r\nand this is the next line."
DISP_DIB=FILE, e:\riffadd\files\dib1.dib
ICMS=FILE, e:\riffadd\files\file2.txt
IPLT=STRING, "This is the palette."

Interactive Mode

In interactive mode, RIFF Add takes additions from the user interface. Specify the chunk type using the Chunk Type drop-down list, specify text using the Text edit field, specify bitmaps using Display DIB, and specify files using the Browse button.


RIFF Walk

Windows 95/98

The RIFF Walk tool (RIFFWALK.EXE) "walks" the structure of a RIFF file and displays the RIFF chunks contained in the file. It can verify the structure of .AVI and .WAV files.

The following is the command-line syntax for RIFF Walk:

riffwalk [-dx] [-fx] [-j] [-m] [-x] RiffFile
-d x
Specifies the maximum depth to descend.
-f x
Specifies the level of detail to use when expanding chunks.
-j
Indicates that "junk" chunks should be listed.
-m
Expand .AVI "movi" LIST chunks.
-x
Provide a hex dump of chunks that are not expanded.
RiffFile
Specifies the RIFF file.


Video Capture

The Video Capture tool (VIDCAP.EXE or VIDCAP32.EXE) enables you to capture video sequences and images from your capture board. You can capture sequences and images from a VCR, videodisc player, or video camera.

Video Capture provides two modes for capturing video sequences:

  • Real-time capture
  • Step-frame capture

Real-time capture processes a video sequence and audio as the events occur naturally, or as the video source plays without interruption. Step-frame capture pauses the video source as it collects each frame (image) of data. If audio is also selected, this capture mode rewinds the media in the video source and collects audio data as the video source plays a second time.

Real-Time Capture

A video source for real-time capture (such as a video camera or videodisc) provides an uninterrupted stream of information to the capture hardware. The capture hardware copies each frame of the video sequence (and each portion of audio) and transfers it to the hard disk before the next frame of data enters the capture hardware. A video frame contains one image of the video sequence.

Real-time capture demands a fast computer and hard disk. The computer must process and store each incoming video frame before the next frame is received in the capture board. If the system lags during capture, frames of video data are dropped (lost).

Step-Frame Capture

Step-frame capture collects video frames from a video sequence in a series of steps. In step-frame capture, frames are captured one at a time, generally from a paused video device. You can perform step-frame capture manually, advancing the video source using the controls on the video device. Video Capture also provides automatic step-frame capture for video devices that support the Media Control Interface (MCI). With this method, Video Capture issues frame-advance commands to the source device and captures the sequence frame-by-frame. When Video Capture finishes capturing the current frame, it advances the video source to the next capture point.

Step-frame capture provides an alternative for systems that cannot process a video sequence in real time. Because the system can fully process a video frame before contending with the next frame, you can use larger frame sizes and color formats, and you can optionally compress the video sequence during capture. When a step-frame capture is complete, you can capture the audio segment associated with the video frames by playing the source video a second time.

For more information on configuring and using Video Capture, see the help file VIDCAP.HLP included in the SDK.


Doc File Viewer

The DFView utility displays the contents of a compound file.

The following is the DFView command-line syntax:

dfview DocFile

where DocFile is the name of the compound document.

To load the file after starting DFView, click Open DocFile from the File menu. After the file has been loaded, DFView displays its storage hierarchy in one window and its stream contents in another window.

In the storage hierarchy window, storages are represented by folders and streams are represented by documents. Double clicking a closed folder expands the tree at that point. Double clicking an open folder collapses the tree at that point. Double clicking a document opens a stream contents window.

In the stream contents window, streams are displayed using a simple hex-dump format. The first number is the offset of the bytes within the stream. The next sixteen number are the values of the bytes found in the stream. They are displayed in two groups of eight bytes each. The sixteen characters at the end of the line are the ASCII representation of the sixteen byte values. Byte values which do not have a visual ASCII representation are displayed as periods.


Data Object Viewer

The DObjView utility displays objects that support the IDataObject interface. When a data object is retrieved from the clipboard or a drag-drop operation, its data formats are enumerated and displayed in the main window of this utility.

For more information, see the help file, OleTools.Hlp, that is included with the Platform SDK.


Running Object Table Viewer

The IROTView utility displays the contents of the running object table. IROTView displays all registered monikers in the main window. The display is updated whenever the application receives the focus. You can also force an update by clicking Update from the menu.

The status window displays the following information about the selected moniker:

  • display name
  • reduced display name
  • display name of the anti-moniker
  • moniker components
  • 32-bit hash value associated with the moniker
  • the moniker running state
  • the last time the moniker's data was updated
  • the moniker's type


Register Server

The RegSvr32 utility installs a DLL as an in-process server. It invokes one or more functions that are implemented by the application, and exported by name by the DLL. The primary task of these functions is to create or delete appropriate registry entries. The following functions can be invoked by RegSvr32.

  • DllRegisterServer is used for installing DLLs. It should create any necessary registry keys.
  • DllUnregisterServer is used for uninstalling DLLs. It should delete any registry keys that are no longer needed.
  • DllInstall is used for both installing and uninstalling DLLs. It can be used in addition to DllRegisterServer and DllUnregisterServer, or in place of them. It is intended for DLLs that can be installed in more than one way. Unlike DllRegisterServer and DllUnregisterServer, which take no arguments, DllInstall takes two arguments. The first is a Boolean value that specifies whether the DLL is being installed (TRUE) or uninstalled (FALSE). The second is a string that can be used to specify which installation procedure to use.

The following is the RegSvr32 command-line syntax.

regsvr32 [flag1 [flag2 ...] DllName
/u
Uninstall the DLL. If the /i flag is not included DllUnregisterServer will be invoked.
/i:"string"
Invoke DllInstall. If the /u flag is included, DllInstall is instructed to uninstall the DLL, by setting the first parameter to FALSE. Otherwise, the first parameter will be set to TRUE, and DllInstall will install the DLL. The string following the colon will be passed in as the second parameter to DllInstall. It is used to specify which installation procedure is to be used. If /i is used without the colon and string literal, the second parameter of DllInstall will be set to NULL. Unless the /n flag is included, DllRegisterServer or DllUnregisterServer will also be invoked.
/n
Do not invoke DllRegisterServer or DllUnregisterServer. This flag can only be used in combination with /i.
/s
Silent.
/c
Console output.

If no flags are specified, RegSvr32 will install the DLL by invoking DllRegisterServer.

To register a DLL named DllName.Dll by invoking its DllRegisterServer function, use the following command:

regsrvr32 dllname.dll

To unregister the DLL with DllInstall's "uninstall_1" procedure without also invoking DllUnregister, use the following command:

regsrvr32 /u /n /i:"uninstall_1" dllname.dll


Help Compiler

Microsoft Windows help provides online help for users working with a Win32-based application. Windows help provides a practical way to present information about your application in a format users can access easily.

The Help Topics dialog box contains a Contents tab, an Index tab, and a Find tab. The Contents tab contains a hierarchical view of the information that the user can use to navigate the information. The view contains books, which can contain topics or other books. The Index tab contains keywords for one or more help files. The Find tab provides full-text search capability for any help file.

  • About Windows Help Files
  • Using Help in a Windows Application


About Windows Help Files

Windows help files contain the following information elements:

  • text in multiple fonts, sizes, and colors.
  • secondary windows
  • cross-reference jumps
  • pop-up windows
  • bitmaps and metafiles
  • segmented-graphics bitmaps (with embedded hot spots)
  • video files (.avi)

To create a help file, you need to create the following files:

  • topic
  • graphics
  • help project

A topic file contains the text for the help topic and contains the help statements and macros that define the format of the text and the position of graphics in each topic. The graphics files contain the bitmaps and metafiles you want to display in the topics. The project file contains a description of how to build the help file. The contents file specifies the information in the Contents tab.

To build the final help file, use the Microsoft Help Workshop (HCW.EXE) . The compiler combines the topic, graphics, and project files to create a single help file (with the filename extension .HLP) that you can open and view by using Windows Help. For more information, see the Help Author's Guide (HCW.HLP) included with the Help Workshop.


Creating Topic Files

A topic file contains help text, as well as the statements and macros that define the format of the text and the position of the graphics. Every topic file consists of one or more topics. A topic is any distinct unit of information, such as a contents screen, a conceptual description, a set of instructions, a keyboard table, a glossary definition, a list of jumps, a picture, and so on.

Windows Help displays only one topic at a time, but a user can view any topic in a help file by using a link to the topic or searching for keywords associated with the topic.

You create topic files directly by using a text editor and inserting help statements. You can create them indirectly by using a word processor that generates rich-text format (RTF) files. The help statements are an extended subset of the RTF statements, which provide a wide variety of formatting capabilities.

For complete syntax of the RTF commands, see the Help Author's Guide (HCW.HLP) included with the Help Workshop.


Declaring Character Set, Fonts, and Colors

When you create a topic file, you must ensure that the entire contents of the file are enclosed in braces ({ }). The first statement in the file must be the \rtf statement; it immediately follows the first opening brace. You should follow the \rtf statement with an \ansi statement (or a similar statement) that specifies the character set used in the file. The following example shows the general form for a topic file:

{\rtf1\ansi
    .
    .
    .
}

You must declare the names of the fonts you use in the file by using a \fonttbl statement. The \fonttbl statement, enclosed in braces, contains a list of font and family names and specifies a unique number for each font. You use these numbers with \f statements later in the file to set specific fonts. The following \fonttbl statement assigns font numbers 0, 1, and 2 to the TrueType® fonts Times New Roman, Courier New, and Arial, respectively:

{\fonttbl
\f0\froman Times New Roman;
\f1\fdecor Courier New;
\f2\fswiss Arial;}

You should also use the \deff statement to set the default font for the file. Windows Help uses this default font if no other font is specified. The following example sets the default font number to zero, corresponding to the Times New Roman font specified in the previous \fonttbl statement:

\deff0

If you use specific text colors or choose not to rely on the default text colors set by Windows, you must define your colors by using a \colortbl statement. The \colortbl statement, enclosed in braces, defines each color by specifying the amount of each primary color (red, green, and blue) used in it. The statement implicitly numbers the colors consecutively starting from zero. You use these color numbers with \cf statements later in the file to set the color. The following example creates four colors (black, red, green, and blue):

{\colortbl
\red0\green0\blue0;
\red255\green0\blue0;
\red0\green128\blue0;
\red0\green0\blue255;}

Although it is not shown here, you can put a semicolon immediately after the \colortbl statement to define the default color as 0.


Defining Individual Topics

Each topic starts with one or more \footnote statements and ends with a \page statement. All text and graphics specified between these statements belong to the topic.

Every topic must have a context string. Windows Help uses the context string to locate the topic when the user requests to view it. You assign a context string to a topic by using the \footnote statement and the number sign (#) footnote character. Context strings can consist of letters, digits, and the underscore character (_). To prevent conflicts, each context string in a help file must be unique.

You can also assign a title to the topic by using the \footnote statement and the dollar sign ($) footnote character. Windows Help uses the title to identify the topic. You must provide a title if you assign keywords to the topic.

The following example defines a small topic having the context string "topic1" and the title "My Topic":

#{\footnote topic1}
${\footnote My Topic}
This is my first topic.
\par
\page

In general, you use the \par statement to mark the end of each paragraph. In this example, the \par statement marks the end of the only paragraph in the topic.

You can add a macro to a topic by using the \footnote statement and the exclamation point (!) as the footnote character. For example, the following \footnote statement adds the CopyTopic macro to the topic:

!{\footnote CopyTopic()}

Windows Help executes the macro each time it displays the topic.


Setting Font Size and Name

You can set the font name and size by using the \f and \fs statements. The name is set by using a font number specified in the \fonttbl statement. The size of the font is specified in half-points. The following example sets the text to 10-point Times New Roman (if the \fonttbl statement matches the example in Declaring Character Set, Fonts, and Colors):

\f0\fs20

Once you set the font name and size, the settings apply to all subsequent text up to the next \plain statement or until you change the name or size by using the \f or \fs statement again. The \plain statement resets the name and font to the defaults. The default font name is as set by the \deff statement; the default font size is 12 points.


Setting Space Before and After Paragraphs

You can set the amount of space before and after each paragraph by using the \sb and \sa statements. These statements let you control the amount of space that appears between paragraphs. You specify the space in twips. (A twip is 1/1440 inch, or 1/20 of a printer's point). The following example sets the space before a paragraph to 360 twips:

\sb360
This paragraph has 360 twips space immediately before it.
\par
This paragraph also has 360 twips before it.
\par

Once you set the space before or after a paragraph, the spacing applies to all subsequent paragraphs up to the next \pard statement or until you change the spacing by using the \sa and \sb statements again. The \pard statement restores the default spacing.


Setting the Left and Right Indents

When Windows Help displays its window, it automatically creates left and right margins and wraps text to fit within these margins. The margins are positioned slightly within the left and right edges of the window to prevent text in the topic from being clipped by the window.

You can override these margins by setting the left and right indents for a paragraph. The \li and \ri statements set an indent to a position relative to the corresponding left and right margins. For example, the following paragraph is indented 1 inch (1440 twips) from the left margin:

\li1440
This paragraph is indented 1 inch.
\par \pard
This paragraph is not indented.

Once indents are set, they apply to all subsequent paragraphs up to the next \pard statement. Note that the \pard statement must follow the \par statement that ends the paragraph to be indented.

You can set an indent for the first line in a paragraph by using the \fi statement. This allows you to create paragraphs with hanging indents. It is also useful for creating two-column lists.


Setting Tab Stops

You can set tab stops by using the \tx statement. You can use one or more \tx statements, each setting a specific position in twips relative to the left margin. Once you have set tab stops, you can use the \tab statement to align subsequent text with the next tab. The tab settings remain active until you use the \pard statement. The following example creates a two-column list by using a tab stop and paragraph indenting:

\fi-1440\li1440\tx1440
left
\tab
right
\par
left
\tab
right
\par
\pard


Breaking Lines

Ordinarily, Windows Help wraps all lines in a paragraph, fitting as many words on a line as will fit between the current left and right indents. You can force Windows Help to break a line at a given place by using the \line statement. You can control wrapping by using the \keep and \pard statements.

The following example uses the \keep statement to turn off word wrapping for three short lines and uses the \pard statement to restore the default properties:

\keep
3 pairs black socks\line
5 pairs blue socks\line
2 pairs brown socks\line
\par
\pard

The following example uses the \keep and \pard statements to create three nonwrapping paragraphs:

\keep
3 pairs black socks
\par
5 pairs blue socks
\par
2 pairs brown socks
\par
\pard


Creating Links and Pop-up Topics

Windows Help displays only one topic at a time. To enable users to view other topics, you must create hot spots that link your topics to other topics. You create a hot spot by using the \strike, \ul, or \uldb statement and a corresponding \v statement. When you create a link, you provide the text for the hot spot and the context string for the topic that is to be jumped to or displayed. The following example creates a hot spot named Glossary and establishes a link from the hot spot to the topic having the context string "glo1":

You can find a list of terms used in this
help file in the {\uldb Glossary}{\v glo1}.

When Windows Help displays the topic with this hot spot, it places a line under the word Glossary and colors the word green. The context string is not shown, but if the user clicks on the hot spot, Windows Help jumps to and displays the corresponding topic.

The \strike and \uldb statements are used to create jumps to other topics. The \ul statement creates a link to a pop-up topic. Windows Help displays pop-up topics in a pop-up window and leaves the current topic in the main window.

You can also associate a help macro with a hot spot in a topic. For example, the following \uldb and \v statements create a hot spot for the ExecProgram macro:

{\uldb Clock}{\v !ExecProgram("clock.exe", 1)}

Windows Help executes the macro whenever the user chooses the hot spot. Windows Help continues displaying the topic while it executes the macro, unless the macro causes a jump to another topic.


Creating a Keyword List

You can also enable users to find and view topics by assigning keywords to the topics. You assign a keyword by using the \footnote statement and the letter K as the footnote character. Windows Help collects all keywords in a help file and displays them in its Index tab. Using this tab, a user can select a keyword and view the help topics associated with it. The following example assigns the keyword "Sample Topics" to the current topic:

#{\footnote topic1}
${\footnote My Topic}
K{\footnote Sample Topics}
This is my first topic.
\par
\page

If a keyword begins with the letter K, you must place an extra space before the word. Multiple keywords for a topic are separated by semicolons.

A keyword can be assigned to any number of topics. When the user selects the keyword in the Index tab, Windows Help displays all topics associated with the keyword. The user then picks the one to view.

You can also create alternative keywords for a help file for use with the WinHelp function.


Creating Browse Sequences

You can enable users to browse through a sequence of help topics by creating a browse sequence and adding browse buttons to your help file. A browse sequence typically consists of two or more related topics that are intended to be read sequentially. You create a browse sequence by using the \footnote statement and the plus-sign (+) footnote character to assign a sequence identifier. The following example assigns a sequence identifier to the topic titled "A Topic":

#{\footnote topic5}
${\footnote A Topic}
+{\footnote shorttopics}
This is one topic in a browse sequence.
\par
\page

Windows Help adds topics with sequence identifiers to the browse sequence and determines the order of topics in the sequence by sorting the identifiers alphabetically. If two topics have the same identifier, Windows Help assumes that the topic that was compiled first is to be displayed first.

Windows Help uses the sequence only if the browse buttons have been enabled. You can enable the buttons by placing the following statements in the help project file:

[CONFIG]
BrowseButtons()

For more information about the project file, see Creating Help Project Files.

You can create more than one browse sequence in a help file by using sequence numbers with sequence identifiers. The sequence number consists of a colon (:) followed by an integer. Windows Help combines all topics having the same sequence identifier (but different sequence numbers) into a single browse sequence and determines the order of the topics by sorting them alphabetically. To ensure that numerals are sorted correctly, they should have the same number of digits. For example, the numerals 1 through 10 should be 01 through 10.

#{\footnote topic10}
${\footnote Alpha Topic #3}
+{\footnote alpha:3}
This topic is part of the alpha browse sequence.
\par
\page


Embedding Graphics

You can add bitmaps and metafiles to your help files by using the bml, bmc, and bmr statements. These statements take the name of a graphics file and insert the corresponding bitmap or metafile into the help file at the specified position.

Windows Help requires graphics files to be in one of the following formats:

  • bitmap (.BMP)
  • metafile (.WMF)
  • multiple-resolution bitmap (.MRB)
  • segmented-graphics bitmap (.SHG)

Multiple-resolution bitmaps can be created by using the Microsoft Multiple-Resolution Bitmap Compiler (MRBC). Segmented-graphics bitmaps can be created by using Microsoft Windows Hotspot Editor.

Although the \pict statement can also be used to add bitmaps and metafiles to a help file, the bitmap or metafile data must be inserted into the topic file rather than specified as a separate file.


Inserting a Bitmap in Text

You can insert a bitmap into a paragraph as if it were a character by using the bmc statement. The statement aligns the bottom of the bitmap with the base line of the current line of text and places the left edge of the bitmap at the next character position. The following example inserts a bitmap into a line of text:

Press the {bmc enter.bmp} key to complete the task and return to
the main window.

Because the bitmap is treated as text, any paragraph properties assigned to the paragraph also apply to the bitmap. Windows Help places text following the bitmap on the same base line at the next available character position.

In general, bitmaps inserted as characters should be clipped to the smallest possible size. Any extra white space at the top or bottom of the bitmap image affects the alignment of the bitmap with the text and may affect the spacing between lines.

You must not specify negative line spacing for paragraphs that contain bmc statements. Doing so might cause the bitmap to appear on top of the paragraph.


Wrapping Text Around a Bitmap

You can place a bitmap at the left or right margin of the Help window and have subsequent text wrap around the bitmap by using the bml or bmr statement. The bml statement inserts a bitmap at the left margin; bmr inserts it at the right.

If you want text to wrap around a bitmap, you must place the bml or bmr statement at the beginning of a paragraph. Windows Help aligns the start of the paragraph with the top of the bitmap and wraps around the left or right edge of the bitmap. The following example places the bitmap at the left margin and subsequent text wraps around its right edge:

{bml mybitmap.bmp}
The text in this paragraph wraps around
the right edge of the bitmap.
\par

If you place a bml or bmr statement at the end of a paragraph, Windows Help places the bitmap under the paragraph instead of wrapping the text around the bitmap. If you do not want text to wrap around a bitmap, place \par statements immediately before and after the bml or bmr statement.


Using a Bitmap as a Hot Spot

You can use bitmaps as hot spots. This enables you to create graphics, such as icons or buttons, and use them as "jumps" to particular topics or as hot spots for macros. The following example uses the bitmap in the MYBUTTON.BMP file to create a link. When the user clicks the bitmap, Windows Help jumps to the topic identified by the context string "topic15":

{\strike {bml mybutton.bmp}}{\v topic15}

You can also divide a single bitmap into several hot spots and assign a different link or macro to each hot spot. Such bitmaps, called segmented-graphics bitmaps, are created by using Hotspot Editor. For example, if you have a bitmap of a dialog box, you can assign links to each of the control windows in the dialog box, enabling the user to click a control window and view information about it. Segmented-graphics bitmaps already contain the context strings needed for the links; only a bml or bmr statement is needed to insert the bitmap. The \strike and \v statements must not be used.

{bml mydialog.shg}


Multiple-Resolution Bitmaps

A multiple-resolution bitmap is a single bitmap file that contains one or more bitmaps that have been marked for use with specific displays, such as the CGA, EGA, VGA, or 8514 displays. You use multiple-resolution bitmaps to avoid problems associated with displaying bitmaps designed for a single type of display. Single-resolution bitmaps can have the following problems:

  • Appear too big or too small on displays having different resolutions
  • Appear stretched or compressed on displays with different aspect ratios
  • Lack colors or use unintended colors on displays with different color capabilities

You create multiple-resolution bitmaps by using MRBC. The compiler, an MS-DOS program, has the following command-line syntax:

mrbc [/s] filename

The filename parameter specifies the name of a Windows bitmap file. Typically, you specify several filenames, one for each type of display. Wildcards can be used. The compiler uses the filename of the first bitmap file as the name of the output file but gives the output file the filename extension .MRB. The following example combines the bitmap files MYBUTTON.EGA, MYBUTTON.VGA, and MYBUTTON.854 into the multiple-resolution bitmap file MYBUTTON.MRB:

mrbc mybutton.ega mybutton.vga mybutton.854

In this example, the compiler checks the biXPelsPerMeter and biYPelsPerMeter members of the BITMAPINFOHEADER structure in each bitmap file to determine the display type for the bitmap. If these members are set to zero, the compiler prompts for the display type with a message such as the following:

Please enter the monitor type for the bitmap mybutton.ega:

You must enter at least the first character of one of the following display-type names: CGA, EGA, VGA, or 8514. The compiler sets the display type you specify, but it does not check that the type is valid. For example, if you specify VGA for an EGA bitmap, the compiler marks it as a VGA bitmap. The result may be undesirable.

The /s option, specifying silent mode, speeds up compilation if the names of the bitmap files conform to the MRBC filename convention. If you use the /s option, the compiler uses the first character of the filename extension to determine the display type for the bitmap, as described in the following list:

Letter | Meaning
C | CGA bitmap
E | EGA bitmap
V | VGA bitmap
8 | 8514 bitmap

If the filename extension starts with any other character, MRBC assumes a VGA bitmap. The following example creates the multiple-resolution bitmap file MYBUTTON.MRB, containing bitmaps for EGA, VGA, and 8514 displays:

mrbc /s mybutton.ega mybutton.vga mybutton.854

The compiler never writes over existing multiple-resolution bitmap files. If the output file already exists, the compiler displays an error message.

You insert multiple-resolution bitmaps into your help file by using the same statements as for Windows bitmaps. For example, the following bmc statement inserts the bitmaps from the MYBUTTON.MRB file:

Click the {bmc mybutton.mrb} button to complete the task and
return to the main window.

Before displaying a multiple-resolution bitmap, Windows Help checks the display type for the computer and then selects the bitmap that has the closest matching resolution, aspect ratio, and color capabilities. Windows Help never displays more than one bitmap from a multiple-resolution bitmap file.


Creating Help Project Files

The following topics describe the format and contents of the help project file (.HPJ) used to build the help file:

  • Project File Sections
  • Using Macros in Project Files
  • Sample Project File

The project file contains all the information the Microsoft Help Workshop needs to combine topic files and other elements into a help file.

The project file is a text file divided into sections. A number of these sections should be managed through the Help Workshop, rather than through a text file as shown here. For more information, see the Help Author's Guide (HCW.HLP) included with the Help Workshop.


Project File Sections

Every project file consists of one or more sections. Each section has a section name, enclosed in brackets ([]), that defines the purpose and format of statements and options in the section. Following are the sections used in project files:

Section | Description
[ALIAS] | Assigns one or more context strings to the same topic.
[BAGGAGE] | Lists files that are to be placed within the help file (which contains its own file system).
[BITMAPS] | Specifies bitmap files. This section is not required if the project file lists a path for bitmap files by using the BMROOT or ROOT option.
[BUILDTAGS] | Specifies valid build tags.
[CONFIG] | Specifies help macros that define nonstandard menus and buttons used in the help file. This section is required if the help file uses any of these features.
[CONFIG:x] | Contains one or more macros that Windows Help runs when opening the corresponding window, x.
[FILES] | Specifies topic files to be included in the build. This section is required.
[MAP] | Associates topic identifiers with context numbers.
[MACROS] | Associates macros with keywords.
[OPTIONS] | Specifies options that control the build process. If this section is used, it should be the first section listed in the project file, so that the options will apply during the entire build process.
[WINDOWS | Defines the characteristics of the primary Help window and the secondary-window types used in the help file. This section is required if the help file uses secondary windows.

Every project file requires a [FILES] section. This section names the topic files. Most project files also have an [OPTIONS] section that specifies how to build the help file. A very useful option in the [OPTIONS] section is the COMPRESS option, which specifies whether the help file should be compressed or uncompressed. Compressing a help file reduces its size considerably and saves valuable disk space. For more information, see the Help Author's Guide (HCW.HLP) included with the Help Workshop.

The following example creates a compressed help file from two topic files, MAIN.RTF and MENUS.RTF:

[OPTIONS]
COMPRESS=TRUE

[FILES]
MAIN.RTF
MENUS.RTF


Using Macros in Project Files

You can add macros to the [MACROS] section of a project file. These macros are run whenever a user selects the specified keyword in the index.

You can create new menu items and buttons for Windows Help by using such macros as CreateButton and InsertMenu. These macros define other help macros and associate them with the menu items and buttons. Windows Help executes these macros when the user chooses a corresponding menu item or button. Macros that create help buttons, menus, or menu items remain in effect until the user quits Windows Help or opens a new help file.

You can extend the capabilities of Windows Help by developing your own dynamic-link libraries (DLLs) and defining help macros that call functions in the libraries. To define help macros that call DLL functions, you must register each function and its corresponding library by using the RegisterRoutine macro in the [CONFIG] section of the project file.


Sample Project File

The following example is a sample project file for the Cardfile application. Comments, marked by a beginning semicolon (;), indicate the purpose of each section in the file:

; Options used to define the Help title bar and icon
[OPTIONS]
ROOT=C:\HELP
BMROOT=C:\HELP\ART
CONTENTS=cont_idx_card
TITLE=Cardfile Help
ICON=CARDHLP.ICO
COMPRESS=OFF
WARNING=3
REPORT=ON
ERRORLOG=CARD.BUG

; Files used to build Cardfile Help
[FILES]
RTFTXT\COMMANDS.RTF
RTFTXT\HOWTO.RTF
RTFTXT\KEYS.RTF
RTFTXT\GLOSSARY.RTF

; Button macros and Using help file
[CONFIG]
CreateButton("btn_up", "&Up", "JumpContents('HOME.HLP')")
BrowseButtons()
SetHelpOnFile("APPHELP.HLP")

; Secondary-window characteristics
[WINDOWS]
picture = "Samples", (123,123,256,256), 0, (0,255,255), (255,0,0)


Windows Help Statements and Macros

The following topics describe the syntax and purpose of statements and macros used in topic and project files:

  • Help Statement Syntax
  • Help Macro Syntax

The help statements define the format and placement of text and graphics in the help file. The help macros define actions to take while the help file is being viewed, such as creating custom buttons and carrying out menu commands.


Help Statement Syntax

Help statements are an extended subset of tokens defined by the rich-text-format (RTF) standard. The statements specify character and paragraph properties, such as font, color, spacing, and alignment for text in the help file.

Help statements are contained in topic files, which are specified in the [FILES] section of a project file. A topic file consists of statements, groups, and unformatted text. Each statement consists of a backslash (\) followed by a statement name. For example, the following line demonstrates usage of the \tab statement:

left column\tab right column

Statements must be separated from subsequent text or statement parameters by a delimiter. A delimiter can be one of the following:

  • A space.
  • A digit or minus sign, which indicates that a numeric parameter follows. The subsequent digit sequence is then delimited by a space or character other than a letter or digit.
  • Any character other than a letter or digit.

When a space is used as a delimiter, the compiler discards it. If any other character is used, the compiler processes it as text or the start of another statement. For example, if a backslash is used as a delimiter, the compiler interprets it as the beginning of the next statement.

A group consists of help statements and text enclosed in braces ({}). Formatting specified within a group affects only the text within that group. Text within a group inherits any formatting of the text preceding the group.

Unformatted text consists of any combination of 7-bit ASCII characters. Although characters whose values are greater than 127 are not permitted in topic files, the \' statement can be used to insert them in the final help file. The compiler treats spaces as part of the text, but it discards carriage return and linefeed characters.

Although the compiler supports many RTF tokens, it does not support them all. The compiler ignores any RTF statement that is not explicitly defined in the Help Author's Guide (HCW.HLP). Furthermore, the compiler may interpret an RTF token differently than it is specified by the standard. For example, the standard specifies that the \uldb statement indicates a double underline, but the compiler uses this statement to indicate a hot spot.


Help Macro Syntax

Help macros specify actions that Windows Help takes when it loads help or displays a topic. A macro consists of a macro name and parameters enclosed in parentheses.

Macro names specify the action to take, such as creating buttons or inserting menu items. The names are not sensitive to case, so any combination of uppercase and lowercase letters may be used.

Macro parameters specify the files, buttons, menus, or topics on which to carry out the action. The parameters must be enclosed in parentheses and separated by spaces. Parameters in many macros must also be enclosed in quotation marks. This is especially true if the parameter contains space characters. The valid quotation characters are the matching double quotation marks (" ") and the opening and closing single quotation marks (' '). If a quotation character is needed as part of a parameter rather than to enclose a parameter, the parameter should be enclosed in single quotation marks. When you use single quotation marks in this case, you can omit the backslash escape character for the double quotation marks, as shown in the following:

'command "string as parameter"'

Macros can be used as parameters in other macros. In most cases, embedded macros must be enclosed in quotation marks. If the embedded macro also has quoted parameters, the quotation character that is used must be different than the quotation characters enclosing the macro. The following example shows the correct way to use nested quotation marks:

CreateButton("time_btn", "&Time", "ExecProgram('clock', 0)")

Help macros can be combined into macro strings by separating the macros with semicolons (;). The compiler processes the macro string as a unit and executes the individual macros sequentially.


Using Help in a Windows Application

Win32-based applications can offer help to their users by using the WinHelp function to start Windows Help and display topics in the application's help file. The WinHelp function gives a Win32-based application complete access to the help file, as well as to the menus and commands of Windows Help. Many applications use WinHelp to implement context-sensitive help. Context-sensitive help enables users to view topics about specific windows, menus, menu items, and control windows by selecting the item with the keyboard or the mouse. For example, a user can learn about the Open command on the File menu by selecting the command (using the direction keys) and pressing the F1 key.

  • Choosing Help from the Help Menu
  • Choosing Help with the Keyboard
  • Choosing Help with the Mouse
  • Searching for Help with Keywords
  • Displaying Help in a Secondary Window
  • Canceling Help


Choosing Help from the Help Menu

Every application should provide a Help menu to allow the user to open the help file with either the keyboard or the mouse. The Help menu should contain at least one Contents menu item that, when chosen, displays the Contents tab or the main topic in the help file. To support the Help menu, the application's main window procedure should check for the Contents menu item and call the WinHelp function, as in the following example:

case WM_COMMAND:
    switch (wParam) {
    case IDM_HELP_CONTENTS:
        WinHelp(hwnd, "myhelp.hlp", HELP_CONTENTS, 0L);
        return 0L;
        .
        .
        .

    }
    break;

You can add other menu items to the Help menu for topics containing general information about the application. For example, if your help file contains a topic that describes how to use the keyboard, you can place a Keyboard menu item on the Help menu. To support additional menu items, your application must specify either the context string or the context identifier for the corresponding topic when it calls the WinHelp function. The following example uses a macro to specify the context string IDM_HELP_KEYBOARD for the Keyboard topic:

case IDM_HELP_KEYBOARD:
    WinHelp(hwnd, "myhelp.hlp", HELP_COMMAND,
            (LPSTR)"JumpID(\"myhelp.hlp\",\"IDM_HELP_KEYBOARD\")");
    return 0L;

A better way to display a topic is to use a context identifier. To do this, the help file must assign a unique number to the corresponding context string, in the [MAP] section of the project file. For example, the following section assigns the number 101 to the context string IDM_HELP_KEYBOARD:

[MAP]
IDM_HELP_KEYBOARD   101

An application can display the Keyboard topic by specifying the context identifier in the call to the WinHelp function, as in the following example:

#define IDM_HELP_KEYBOARD 101

WinHelp(hwnd, "myhelp.hlp", HELP_CONTEXT, (DWORD)IDM_HELP_KEYBOARD);

To make maintenance of an application easier, most programmers place their defined constants (such as IDM_HELP_KEYBOARD in the previous example) in a single header file. As long as the names of the defined constants in the header file are identical to the context strings in the help file, you can include the header file in the [MAP] section to assign context identifiers, as shown in the following example:

[MAP]
#include <myhelp.h>

If a help file contains two or more Contents topics, the application can assign one as the default by using the context identifier and the HELP_SETCONTENTS value in a call to the WinHelp function.


Choosing Help with the Keyboard

An application can enable the user to choose a help topic with the keyboard by intercepting the F1 key. Intercepting this key lets the user select a menu, menu item, dialog box, message box, or control window and view help for it with a single keystroke.

To intercept the F1 key, the application must install a message-filter procedure by using the SetWindowsHookEx function. This allows the application to examine all keystrokes for the application, regardless of which window has the input focus. If the filter procedure detects the F1 key, it posts a WM_F1DOWN message (application-defined) to the application's main window procedure. The procedure then determines which help topic to display.

The filter procedure should have the following form:

int CALLBACK FilterFunc(nCode, wParam, lParam)
int nCode;
WORD wParam;
DWORD lParam;
{
    LPMSG lpmsg = (LPMSG)lParam;

    if ((nCode == MSGF_DIALOGBOX || nCode == MSGF_MENU) &&
            lpmsg->message == WM_KEYDOWN && lpmsg->wParam == VK_F1) {
        PostMessage(hWnd, WM_F1DOWN, nCode, 0L);
    }

    DefHookProc(nCode, wParam, lParam, &lpFilterFunc);

    return 0;
}

The application should install the filter procedure after creating the main window, as shown in the following example:

lpProcInstance = MakeProcInstance(FilterFunc, hInstance);
if (lpProcInstance == NULL)
    return FALSE;

lpFilterFunc = SetWindowsHook(WH_MSGFILTER, lpProcInstance);

The filter procedure sends a WM_F1DOWN message only when the F1 key is pressed in a dialog box, message box, or menu. Many applications also display the Contents topic if no menu, dialog box, or message box is selected when the user presses the F1 key. In this case, the application should define the F1 key as an accelerator key that starts Windows Help.

To create an accelerator key, the application's resource-definition file must define an accelerator table, as follows:

1 ACCELERATORS
BEGIN
    VK_F1, IDM_HELP_CONTENTS, VIRTKEY
END

To support the accelerator key, the application must load the accelerator table by using the LoadAccelerators function and translate the accelerator keys in the main message loop by using the TranslateAccelerator function.

In addition to installing the filter procedure, the application must keep track of which menu, menu item, dialog box, or message box is currently selected. In other words, when the user selects an item, the application must set a global variable indicating the current context. For dialog and message boxes, the application should set the global variable immediately before calling the DialogBox or MessageBox function. For menus and menu items, the application should set the variable whenever it receives a WM_MENUSELECT message. As long as identifiers for all menu items and controls in an application are unique, an application can use code similar to the following example to monitor menu selections:

case WM_MENUSELECT:
    /*
     * Set dwCurrentHelpId to the help ID of the menu item that is
     * currently selected.
     */

    if (HIWORD(lParam) == 0)             /* no menu selected    */
        dwCurrentHelpId = ID_NONE;
    else if (lParam & MF_POPUP) {        /* pop-up selected     */
        if ((HMENU)wParam == hMenuFile)
            dwCurrentHelpId = ID_FILE;
        else if ((HMENU)wParam == hMenuEdit)
            dwCurrentHelpId = ID_EDIT;
        else if ((HMENU)wParam == hMenuHelp)
            dwCurrentHelpId = ID_HELP;
        else
            dwCurrentHelpId = ID_SYSTEM;
    }

    else                                 /* menu item selected */
        dwCurrentHelpId = wParam;

    break;

In this example, the hMenuFile, hMenuEdit, and hMenuHelp parameters must previously have been set to specify the corresponding menu handles. An application can use the GetMenu and GetSubMenu functions to retrieve these handles.

When the main window procedure finally receives a WM_F1DOWN message, it should use the current value of the global variable to display a help topic. The application can also provide help for individual controls in a dialog box by determining which control has the focus at this point, as shown in the following example:

case WM_F1DOWN:
    /*
     * If there is a current help context, display it.
     */

    if (dwCurrentHelpId != ID_NONE) {
        DWORD dwHelp = dwCurrentHelpId;

        /*
         * Check for context-sensitive help for individual dialog
         * box controls.
         */

        if (wParam == MSGF_DIALOGBOX) {
            WORD wID = GetWindowWord(GetFocus(), GWW_ID);
            if (wID != IDOK && wID != IDCANCEL)
                dwHelp = (DWORD) wID;
        }

        WinHelp(hWnd, szHelpFileName, HELP_CONTEXT, dwHelp);

        /*
         * This call is used to remove the highlighting from the
         * System menu, if necessary.
         */

        DrawMenuBar(hWnd);
    }

    break;

When the application ends, it must remove the filter procedure by using the UnhookWindowsHookEx function.


Choosing Help with the Mouse

An application can enable the user to choose a help topic with the mouse by intercepting mouse input messages and calling the WinHelp function. To distinguish requests to view help from regular mouse input, the user must press the SHIFT+F1 key combination. In such cases, the application sets a global variable when the user presses the key combination and changes the cursor shape to a question-mark pointer to indicate that the mouse can be used to choose a help topic.

To detect the SHIFT+F1 key combination, an application checks for the VK_F1 virtual-key value in each WM_KEYDOWN message sent to its main window procedure. It also checks for the VK_ESCAPE virtual-key code. The user presses the ESC key to quit Windows Help and restore the mouse to its regular function. The following example checks for these keys:

case WM_KEYDOWN:
    if (wParam == VK_F1) {

        /* If Shift-F1, turn help mode on and set help cursor. */

        if (GetKeyState(VK_SHIFT)) {
            bHelp = TRUE;
            SetCursor(hHelpCursor);
            return DefWindowProc(hwnd, message, wParam, lParam);
        }

        /* If F1 without shift, call help main index topic. */

        else {
            WinHelp(hwnd,"myhelp.hlp",HELP_CONTENTS,0L);
        }
    }
    else if (wParam == VK_ESCAPE && bHelp) {

        /* Escape during help mode: turn help mode off. */

        bHelp = FALSE;
        SetCursor((HCURSOR) GetClassWord(hWnd, GCW_HCURSOR));
    }

    break;

Until the user clicks the mouse or presses the ESC key, the application responds to WM_SETCURSOR messages by resetting the cursor to the arrow and question-mark combination.

case WM_SETCURSOR:
    /*
     * In help mode, it is necessary to reset the cursor in response
     * to every WM_SETCURSOR message. Otherwise, by default, Windows
     * will reset the cursor to that of the window class.
     */

    if (bHelp) {
        SetCursor(hHelpCursor);
        break;
    }

    return (DefWindowProc(hwnd, message, wParam, lParam));

case WM_INITMENU:
    if (bHelp) {
        SetCursor(hHelpCursor);
    }

    return (TRUE);

If the user clicks the mouse button in a nonclient area of the application window while in help mode, the application receives a WM_NCLBUTTONDOWN message. By examining the wParam value of this message, the application can determine which context identifier to pass to WinHelp.

case WM_NCLBUTTONDOWN:
    /*
     * If in help mode (Shift+F1), display context-sensitive
     * help for nonclient area.
     */
    if (bHelp) {
        dwHelpContextId =
            (wParam == HTCAPTION) ?(DWORD) HELPID_TITLE_BAR:
            (wParam == HTSIZE) ? (DWORD) HELPID_SIZE_BOX:
            (wParam == HTREDUCE) ? (DWORD) HELPID_MINIMIZE_ICON:
            (wParam == HTZOOM) ? (DWORD) HELPID_MAXIMIZE_ICON:
            (wParam == HTSYSMENU) ?(DWORD) HELPID_SYSTEM_MENU:
            (wParam == HTBOTTOM) ? (DWORD) HELPID_SIZING_BORDER:
            (wParam == HTBOTTOMLEFT) ? (DWORD) HELPID_SIZING_BORDER:
            (wParam == HTBOTTOMRIGHT) ?(DWORD) HELPID_SIZING_BORDER:
            (wParam == HTTOP) ?(DWORD) HELPID_SIZING_BORDER:
            (wParam == HTLEFT) ?(DWORD) HELPID_SIZING_BORDER:
            (wParam == HTRIGHT) ?(DWORD) HELPID_SIZING_BORDER:
            (wParam == HTTOPLEFT) ?(DWORD) HELPID_SIZING_BORDER:
            (wParam == HTTOPRIGHT) ? (DWORD) HELPID_SIZING_BORDER:
            (DWORD) 0L;

        if (!((BOOL) dwHelpContextId))
            return DefWindowProc(hwnd, message, wParam, lParam);
        bHelp = FALSE;
        WinHelp(hWnd, szHelpFileName, HELP_CONTEXT, dwHelpContextId);
        break;
    }

    return (DefWindowProc(hWnd, message, wParam, lParam));

If the user clicks a menu item while in help mode, the application intercepts the WM_COMMAND message and sends the help request:

case WM_COMMAND:

    /* In help mode (Shift-F1)? */

    if (bHelp) {
        bHelp = FALSE;
        WinHelp(hWnd, szHelpFileName, HELP_CONTEXT, (DWORD)wParam);
        return NULL;
    }


Searching for Help with Keywords

An application can enable the user to search for topics based on full or partial keywords. The following example searches for the keyword "Keyboard" and displays the corresponding topic, if found:

WinHelp(hwnd, "myhelp.hlp", HELP_KEY, "Keyboard");

If the topic is not found, Windows Help displays the Index tab. If more than one topic has the same keyword, Windows Help displays the list of topics in the Topics Found dialog box.

An application can give the user more options in a search by specifying partial keywords. When a partial keyword is given, Windows Help usually displays the Index tab to allow the user to continue the search or return to the application. However, if there is an exact match and no other topic exists with the given keyword, Windows Help displays the topic. The following example opens the Find tab and selects the first keyword in the list starting with the letters Ke:

WinHelp(hwnd, "myhelp.hlp", HELP_PARTIALKEY, "Ke");

When the HELP_KEY and HELP_PARTIALKEY values are specified in the WinHelp function, Windows Help searches the K keyword table. This table contains keywords generated by using the letter K with \footnote statements in the topic file. An application can search alternative keyword tables by specifying the HELP_MULTIKEY value in the WinHelp function. In this case, the application must specify the footnote character and the full keyword in a MULTIKEYHELP structure, as follows:

HGLOBAL hglblmkh;
MULTIKEYHELP FAR* mkh;
PSTR pszKeyword = "Frame";
UINT cb;

cb = sizeof(MULTIKEYHELP) + lstrlen(pszKeyword);

hglblmkh = GlobalAlloc(GHND, (DWORD) cb);
if (hglblmkh == NULL)
    break;
mkh = (MULTIKEYHELP FAR*) GlobalLock(hglblmkh);

mkh->mkSize    = cb;
mkh->mkKeylist = 'L';
lstrcpy(mkh->szKeyphrase, pszKeyword);

WinHelp(hwnd, "myhelp.hlp", HELP_MULTIKEY, (DWORD) mkh);

GlobalUnlock(hglblmkh);
GlobalFree(hglblmkh);

If the keyword is not found, Windows Help displays an error message. If more than one topic has the keyword, Windows Help displays only the first topic.

Applications cannot use alternative keyword tables unless the MULTIKEY option is specified in the [OPTIONS] section of the project file.


Displaying Help in a Secondary Window

An application can display topics in secondary windows instead of in the Windows Help main window. Secondary windows are useful whenever the user does not need the full capabilities of Windows Help.

To display help in a secondary window, the application specifies the name of the secondary window along with the name of the help file. The following example displays the topic having the context identifier IDM_FILE_SAVE in the secondary window named "wnd_menu":

WinHelp(hwnd, "myhelp.hlp>wnd_menu", HELP_CONTEXT, IDM_FILE_SAVE);

The name and characteristics of the secondary window must be defined in the [WINDOWS] section of the project file, as in the following example:

[WINDOWS]
wnd_menu = "Menus", (128, 128, 256, 256), 0

Windows Help displays the secondary window with the initial size and position specified in the [WINDOWS] section. However, an application can set a new size and position by specifying the HELP_SETWINPOS value in the WinHelp function. In this case, the application sets the members in a HELPWININFO structure to specify the window size and position. The following examples sets the secondary window wnd_menu to a new size and position:

HANDLE hhwi;
LPHELPWININFO lphwi;
WORD wSize;
char *szWndName = "wnd_menu";

wSize = sizeof(HELPWININFO) + lstrlen(szWndName);
hhwi = GlobalAlloc(GHND, wSize);
lphwi = (LPHELPWININFO)GlobalLock(hhwi);

lphwi->wStructSize = wSize;
lphwi->x           = 256;
lphwi->y           = 256;
lphwi->dx          = 767;
lphwi->dy          = 512;
lphwi->wMax        = 0;
lstrcpy(lphwi->rgchMember, szWndName);

WinHelp(hwnd, "myhelp.hlp", HELP_SETWINPOS, lphwi);

GlobalUnlock(hhwi);
GlobalFree(hhwi);


Canceling Help

Windows Help requires an application to explicitly cancel help so that Windows Help can free any resources it used to keep track of the application and its help files. The application can do this at any time.

An application cancels Windows Help by calling the WinHelp function and specifying the HELP_QUIT value, as shown in the following example:

WinHelp(hwnd, "myhelp.hlp", HELP_QUIT, NULL);

If the application has made any calls to the WinHelp function, it must cancel help before it closes its main window (for example, in response to the WM_DESTROY message in the main window procedure). An application needs to call WinHelp only once to cancel help, no matter how many help files it has opened. Windows Help remains running until all applications or dynamic-link libraries that have called the WinHelp function have canceled help.


Dialog Box Editor

The Dialog Editor automates the process of creating dialog boxes. You can see your dialogs as you design them without writing and compiling your own resource scripts. The Dialog Editor requires a mouse or equivalent pointing device.

The Dialog Editor works much like a paint program. You design dialogs interactively, placing and moving graphical elements right on the screen. When you complete your design, the Dialog Editor automatically creates the files you need to incorporate the dialogs in your program.

This overview explains how to create dialog boxes and include them in an application. You can use the Dialog Editor's online Help to get more information on specific features.

Note A dialog box that has not been compiled and exists only in resource script form is referred to as a dialog.


Creating a New Dialog

To create your application's dialog

  1. Start the Dialog Editor from the Start menu.
  2. On the File menu, click New.

The properties bar, the rectangular area immediately below the Dialog Editor's menu bar, displays the screen coordinates of the currently selected dialog or control. When a dialog is selected, as it is after you first click New from the File menu, there are also three edit fields on the properties bar:

  • Dlg. Sym., for your symbolic dialog name
  • Caption, for your dialog title
  • A dialog ID field

The small solid rectangles around the dialog border are called resize handles. They show that the dialog is currently selected.

You can use the mouse to resize the dialog with the resize handles, and you can move the dialog with the arrow keys or the mouse. To move the dialog with the mouse, click and drag its title bar or border. The coordinates in the fields on the left side of the properties bar change as you move the dialog.

At times it may be useful to design the dialog in the graphical context in which it will be used. For example, you may wish to see how the dialog box looks against the backdrop of the application (the way users of your application will see it).

To design dialogs using your application as a backdrop

  1. Start your application.
  2. Start the Dialog Editor.
  3. Move the dialog you are designing outside the Dialog Editor window.
  4. Reduce the Dialog Editor window in size and move it to a corner of the display.

You can design the dialog box on the screen where it will eventually appear.


Adding a Control

The toolbox on the right side of the screen contains icons of the mouse pointer and all supplied controls. The mouse pointer, when pressed, indicates that no control has been selected. You can place any of the other controls in a dialog, and you can also create and include your own custom controls.

To add a control to the dialog

  1. In the Toolbox, click one of the control icons.
  2. Click in the dialog.

You can use the mouse to resize a control with its resize handle. You can move a control with the cursor keys when it is selected or by dragging it with the mouse.

When a control is selected or created, the properties bar displays information about it. The Symbol edit field replaces the Dlg. Sym. edit field, and the Text edit field replaces the Caption edit field. The numeric control ID edit field appears for controls just as for dialogs.

You can associate a symbolic name with the control's ID by typing the name in the Symbol edit field. The Dialog Editor assigns each new control in a dialog an ID number. It assigns these numbers sequentially, beginning with the number following the dialog ID. Even if you assigned it a zero-terminated string and deleted the integer ID.


Symbolic Names and ID Numbers

You select the new dialog by clicking anywhere outside a control in the dialog window. The properties bar then displays the dialog's default title, Dialog Title, and the default ID, which is 100 in this case.

Each dialog box in an application needs a unique integer ID. You use the ID in your application source code to tell the system which dialog box to call, and the system uses the ID to search the resource file for the dialog box.

You can associate a symbolic name with the ID by typing the name in the Dlg. Sym. edit field. It's easier to refer to a dialog by a name than by a number. Alternatively you can name a dialog with a zero-terminated string, although this is not as efficient.

To enter a zero-terminated string as a dialog designator

  1. Type the string in the Dlg. Sym. edit field.
  2. Immediately tab to the field on the right (the Dialog ID edit field).
  3. Delete the integer ID.
  4. Press ENTER.

You can give your dialog a title by typing text in the Caption edit field. You can use the TAB key to move the insertion point. From the Dlg. Sym. edit field, the insertion point first tabs to the Dlg. Sym. ID edit field and then to the Caption edit field. You can also reposition the insertion point by clicking the mouse pointer in the edit field you want to use.

When you select or create a control, the Symbol edit field replaces the Dlg. Sym. edit field. You can associate a symbolic name with the control's ID by typing the name in the Symbol edit field, or by selecting it from the list of available symbols (if you have any).


The IDOK, IDCANCEL, and UNUSED Symbols

Because most dialog boxes have OK and Cancel buttons, the system provides defined symbols for these elements.

You use the defined symbol IDOK for an OK button in your dialog. When the user presses ENTER, the system sends your dialog procedure a message as if the OK button had been pressed. IDOK has an ID value of 1.

You use IDCANCEL for a Cancel button in your dialog. When the user presses ESC, it's as if the Cancel button had been pressed. IDCANCEL has an ID value of 2.

Some controls don't need a unique identifier. For example, you won't usually need to access a group box frame, which simply frames other controls. You can assign all such controls the symbol (Unused), which has an ID value of –1.

To display and edit the current symbols, click Symbols from the Edit menu. The Symbols dialog box displays a list box of symbols and corresponding IDs. You can add, change, and delete symbols in the Symbols dialog box.

When you remove a control from a dialog, the symbol and ID for that control remain defined but not in use. You can display unused symbols by checking the Show Unused Symbols Only check box in the Symbols dialog box. You can then delete these unused symbols if you like.

The Text field on the properties bar contains the button's default text, Push.

To assign other text to the button

  1. Type the text for the push button in the Text edit field.
  2. Press ENTER.

For example, you might assign the symbol IDOK to your first push button and give it the text OK, and then press ENTER.

To make the width of a selected control better fit its text, click Size to Text from the Edit menu. However, you cannot size a push button smaller than a default-sized push button. A push button always automatically maintains a margin around its text. The following controls can be sized to their text:

  • Check box
  • Push button
  • Radio button
  • Text
  • Custom controls written to support this feature

To size a control to its text

  1. Select the control.
  2. Click Size to Text from the Edit menu, or press F7.

You can size a single control to fit its text, or you can select a group of controls and size them all at once. If a group of controls is selected, only those controls that support sizing to fit their text will be changed.


Adding More Controls

Dialog boxes often include more than one control — push buttons, list boxes, and check boxes are common. The following topics show you how to add controls and how to edit and organize these controls.

  • Duplicating a Control
  • Adding a List Box
  • Adding Custom Controls


Duplicating a Control

You will probably want to have more than one push button in your dialog.

To add another push button

  1. Hold down the CTRL key.
  2. Drag the existing push button to a new location and drop it.

You might give this second button the symbol IDCANCEL and the label Cancel.

You can repeat this process to create more push buttons. Or you can use the CTRL key when you select controls from the toolbox. If you hold down the CTRL key when you click a toolbox button, the toolbox button stays in the pressed position. You can then click repeatedly in the dialog and place a number of identical controls. When you have all the controls you need of this kind, click the top control in the toolbox, or press ESC when the toolbox has the focus.


Adding a List Box

To add a list box to the dialog, click its icon in the toolbox (fourth row, second column) and drop it into the dialog box. A list box is a box of text strings with a scrollbar on its right side.

The list box appears only as an outline at this stage. You'll see more of the list box in a moment, when you test the dialog.


Adding Custom Controls

When a standard control — such as a list box or edit field — doesn't meet your needs, you can create a custom control that performs a specific task. For example, the buttons on a toolbar can be custom controls.

The code that defines a custom control resides in either a DLL or, occasionally, in the .EXE file that calls the dialog box. The Dialog Editor supports custom-control DLLs and temporary custom controls, as described in the following table.

Custom control | Description
DLL | A dynamic-link library (DLL) that defines one or more custom control classes.
Temporary | A place holder for a custom control defined elsewhere. The Dialog Editor creates a gray rectangle to indicate the control's location and size. You can set the temporary control's class name, size, and other attributes to match the ones used by the final custom control.

After a custom-control DLL is opened by the Dialog Editor, it remains available between Dialog Editor sessions. Temporary custom controls are not saved between sessions.

When the Dialog Editor opens a .DLG file that contains a custom control, it searches its list of custom-control DLLs to find a match. If a match is found (the controls have the same class name), the Dialog Editor uses the information in the DLL to display the custom control. If a match is not found, the Dialog Editor creates a temporary custom control with the given class name.

The Dialog Editor replaces any temporary custom control during an editing session when you open a DLL custom control with the same name.

To add a new temporary custom control

  1. From the File menu, click New Custom. The New Temporary Custom Control dialog box appears.
  2. Type a name for the custom control in the Class Name edit field.
  3. Optionally, change the other Control Defaults.
  4. Choose OK.

The Dialog Editor adds the temporary control to the list of available custom controls. To use the temporary control, click the custom control tool. You can use the following method to add either a temporary custom control or a custom control DLL to a dialog box:

To add a custom control

  1. Click the Custom Control (bottom right) tool on the toolbox.

    If you have more than one custom control installed (either temporary or from DLLs), the Select Custom Control dialog box is displayed. If you only have one custom control, skip to Step 6.

  2. From the Available Controls list box, select the custom control you want to add to the dialog box.
  3. Choose OK.
  4. Move the cursor into the dialog. A rectangle with the "move" icon inside replaces the cursor.
  5. Press and hold the mouse button to see an outline of the control. The coordinates for the location of the control are displayed in the properties bar.

    You cannot move the outlined control outside of the dialog once you have pressed the mouse button.

  6. Drop the control by releasing the mouse button. The custom control is centered over the point where you released the mouse button.


Editing Groups of Controls

You'll often find it useful to edit an entire group of controls. You can drag, cut, copy, paste, align, and size a group of controls.

First, enlarge the OK button by selecting it and then dragging one of its corner handles with the mouse. Now select all three buttons by dragging open a rectangle with the mouse. To drag a rectangle open, place the mouse pointer beside a control, then press and hold the left mouse button, and drag the mouse. In this way you can select all the controls that are within or partially within the rectangle boundaries.

Another way to select several controls at a time is to hold down the SHIFT key and click on each control. This is useful for making a group out of a number of scattered controls. You can also toggle the selection state of each control without affecting other controls by clicking on that control while holding down the SHIFT key.


The Anchor Control

In a selected group of controls, one of the controls has solid resize handles, while the others have outlined handles. The button with the solid handles is called the anchor control. The anchor serves as a guide for various group alignment and sizing operations. You can change the current anchor in a selected group by clicking any control that is part of the group. Now make the third (unnamed) push button the anchor by clicking it.


Sizing and Aligning a Group

To make all the selected buttons the same size as the anchor button

  1. From the Arrange menu, click Same Size.
  2. Click the top option to make the buttons the same width.
  3. Click Same Size again.
  4. Click the bottom option to make the buttons the same height.

All the buttons become the same size as the anchor button.

The two Push Button items on the Arrange menu control the alignment of push buttons. One centers buttons across the bottom of the dialog box, and the other arranges them down the right side. Use the proper option to arrange the buttons down the right side.


Ordering Controls

You've now built a dialog with three push buttons and a list box. At this stage in the design, you'll often refine the order of controls, that is, the order in which the user will move through them with the TAB key.

When the user of your dialog box presses the TAB key, the focus moves through the controls in order, stopping at each one for which a tab stop is set. Some controls, such as a frame, have no need for a focus. Controls that can use the focus have a tab stop set by default. Each control in your dialog already has a tab stop.


Changing Control Tabbing Order

To see the current tabbing order of your controls, click Order/Group from the Arrange menu. This displays the Order/Group dialog box. All controls in your new dialog are listed in the list box in their current tabbing order, which is the order in which you created them.

If this dialog box were opened in an application, by default the focus would begin with the first control you created, the OK button. The user would probably prefer that the focus begin at the list box.

To change the tabbing order by moving the list box control to the start of the list

  1. Click the list box control from the list in the Order/Group dialog box.
  2. Move the mouse pointer to the start of the list. The mouse pointer changes shape at a valid insertion point.
  3. Click to reposition the list box.


Making Groups

You can also use the Order/Group to group controls in your dialog box. This allows the user to cycle the focus through the members of a group using the arrow keys after moving to a group member with the TAB key.

To be grouped together, controls must be contiguous in the Order/Group list box. Hence you should define groups only after you have the tab order set as you want it.

To make and order a group of controls

  1. From the Arrange menu, click Order/Group. This brings up the Order/Group dialog box.
  2. In the control list box, click the first control you want in a particular group.
  3. Drag the mouse up or down to select the other controls in the group.
  4. Click Make Group.

Groups are shown by lines separating the control names in the list box.

If you have more than one logical group of radio buttons within a dialog, you should group them here so that system will handle their logic properly.


Changing Control Size and Placement

You can also use items on the Arrange menu to size and place groups of controls. Using items on the Arrange menu you can:

  • Align controls along an edge (click Align)
  • Distribute controls evenly with respect to an anchor control (click Even Spacing)
  • Set controls to the same size (click Same Size)
  • Distribute push buttons evenly along the bottom or side of the dialog (click Push Buttons)
  • Change grid and spacing values for editing controls (click Settings)

You might want to experiment with these concepts with the dialog you have just created. Click the Aligning icon in the help file for more information.


Testing Your Dialog

To see how the controls in your dialog work, click Test Mode from the Options menu. Test Mode creates a functioning dialog box for testing. The list box becomes operational with a scrollbar and lines of sample text.

The Dialog Editor inserts lines of sample text. You cannot insert lines of your own text directly into the Dialog Editor. You can scroll the sample text, select it, and see how many lines and characters the box can display, and you can test the changes you make by clicking Order/Group.

You can also use Test Mode to investigate the various style options you can apply to controls and to the dialog box itself (see Dialog and Control Styles).

To quit test mode, click Test Mode from the Options menu, or press ALT+F4.


Dialog and Control Styles

Behind each control and the dialog itself are some associated attributes called styles. Styles govern everything from the way a dialog or control appears to the way it behaves. So far, you've just used the default styles.

Double-click the list box to open its Styles dialog box. You can also open the Styles dialog box for the currently selected dialog box or control by clicking Styles from the Edit menu.

As you can see from the Styles dialog, you have many choices for dialog styles. Test Mode gives you a hands-on way of exploring style. For example, turn on the list box's Extended Selection style, and then close its Styles dialog box. Click Test Mode. A default list box lets you select only one item from its list, but now you can select a range of items from the list box by dragging down the list with the mouse.


Designing Multiple Dialogs for an Application

You've now designed one dialog, but your application may need many. You can work on more than one dialog at a time in the Dialog Editor.

Your first dialog was automatically started for you when you selected New from the File menu. To begin work on a second dialog, click New Dialog from the Edit menu. Your first dialog still exists within the editor. Click Select Dialog from the Edit menu to switch between the dialogs.

You can create as many dialogs as you need for your application. Each dialog is automatically numbered in sequence (100, 200, and so on). To restore a dialog to the state it was in before you selected it for editing, click Restore Dialog. This allows you to abandon your most recent changes.

To continue creating more dialogs for your application, click New Dialog. When you are finished creating the new dialog, you can save it with your other dialogs by choosing the same base file name. This is how you keep all the dialogs together for your application. The Dialog Editor uses the same group of files to keep track of all dialogs that you save together. See the following section for a description of the files the Dialog Editor writes when it saves a group of dialogs.

You can save each dialog you create separately. But if you save them together, the Dialog Editor can avoid conflicts when it assigns ID values, and it can also alert you to conflicts when you choose symbolic names and IDs. Also, for each dialog you save separately, you must place three include statements in your project source code. For the typical application, this might amount to about 100 include statements. When you save an application's dialogs together, however, you need only three include statements for your entire project.

Note If you click New from the File menu and then save with the same base file name as you did before, your previously-saved dialogs are overwritten.


Including Dialogs in an Application

When you save a dialog or dialogs, the editor normally creates three files:

  • The .RES (resource) file, a resource file dedicated to the Dialog Editor. This .RES file is read only by the Dialog Editor and is not the same as the .RES file that is produced by the Resource Compiler and linked into your application.
  • The .DLG (dialog) script, a text file containing DIALOG and CONTROL statements that the Resource Compiler interprets.
  • The .H (include) file, a text file containing #define statements associated with the symbolic names of controls in dialogs. (If you haven't defined any symbolic names in your dialogs, the editor won't create an .H file.)

The .DLG and .H files are used to integrate the current dialogs into your application.

By default, the editor uses the same base name for all three files. Thus, if you use the editor's suggested default name of DIALOGS, the editor writes DIALOGS.RES, DIALOGS.DLG, and DIALOGS.H.

To include dialogs in your application

  1. Use #include statements to include DIALOGS.H and DIALOGS.DLG in your application's resource script (.RC) file. Place the DIALOGS.H statement before the DIALOGS.DLG statement.
    #include "dialogs.h"
#include "dialogs.dlg"
  2. Include DIALOGS.H in your source code.
  3. Write a dialog procedure for each dialog to initialize controls and process their messages.
  4. Compile your source code.
  5. Use the Resource Compiler to compile the .RC file into the application's .RES file.
  6. Link the .RES file into your application's .EXE file.


The DIALOGS.RES File

The DIALOGS.RES and DIALOGS.H files are created by the Dialog Editor. Together they are an archive of all the dialog information. The .RES file contains all the dialog information except the symbolic names you've defined, which are in the .H file.

Don't confuse the .RES file written by the Dialog Editor with the .RES file produced by the Resource Compiler that is linked into your application. The .RES file that the Dialog Editor writes is just an archive for the Dialog Editor's use.

Note You must avoid name conflicts between the two .RES files. Failing to avoid name conflicts will cause unpredictable results.


The DIALOGS.DLG File

When you save a dialog, one of the files the Dialog Editor writes is the .DLG file. This text file contains the information in the .RES file expressed as resource script statements. Each dialog is described in a sequence of statements called a "template."

When you create a dialog in the editor, it has a unique ID number, which becomes a handle to the template. When you want to create an instance of the dialog in your application, you pass this handle to the system in a call to the DialogBox function. The system does the rest. Here's a typical .DLG script file containing two simple dialogs:

100 DIALOG 6, 16, 148, 84
STYLE DS_MODALFRAME | WS_VISIBLE | WS_CAPTION | NOT WS_BORDER | WS_POPUP
CAPTION "Invert"
BEGIN
    PUSHBUTTON      "Push This", 101, 54, 30, 40, 14,
END

200 DIALOG 6, 16, 148, 84
STYLE DS_MODALFRAME | WS_VISIBLE | WS_CAPTION | NOT WS_BORDER | WS_POPUP
CAPTION "Reverse"
BEGIN
    PUSHBUTTON      "Push That", 101, 43, 30, 40, 14,
END

The handles to the two dialogs are 100 and 200. You can also define a corresponding symbolic name for a dialog in the editor. It's easier to use a name than a number in your code.

The Dialog Editor cannot read the DIALOGS.DLG file. The data is saved and read from the .RES file.


The DIALOGS.H File

If you define symbolic names in your dialogs, the Dialog Editor writes them to a .H file.

When you create a dialog control, it gets an ID number. You can also assign a symbolic name to the control, and can refer to the control by name or number in your code. The .H file associates symbolic names with corresponding ID numbers.

A typical .H file looks like this:

#define MYOPTION1  101
#define MYOPTION2  102

You can then refer to controls in this way:

LRESULT CALLBACK FirstDlgProc(HWND hDlg, UINT wMessage, WPARAM wParam, LPARAM lParam)
{
 .
 .
 .
case WM_COMMAND:
   switch (LOWORD(wParam))
   {
      case IDOK :
         // Respond to Ok button here
         break;
      case IDCANCEL :
         // Respond to Cancel button here
         break;
      case MYOPTION1:
         // Respond to MyOption1 button here
         break;
      case MYOPTION2:
         // Respond to MyOption2 button here
         break;
 .
 .
 .
   }
}

Remember that IDOK and IDCANCEL are defined by the system and should be used for the OK and Cancel buttons in your dialog box.


Modifying a Dialog

Because they are text files, you may be tempted to modify the .DLG file and the .H file directly. However, these two files are interdependent, and if you make a change to one, you risk creating a conflict with the other. Also, changes you make in the .DLG file won't become a permanent part of a dialog because the .DLG file is only written by the Dialog Editor, not read. The best way to modify a dialog is to load it into the editor and make the changes there.


Using the Editor for Existing Projects

If you begin using the Dialog Editor in an existing project, you may initially find the structure of the project awkward. The project's dialogs may have been written by hand, and the resulting resource script statements may be in an .RC file along with all the other resources for the application. The project's dialog symbols may be in an .H file along with numerous other of the application's symbols. If you don't restructure the project, you'll have to merge files by hand each time you create a dialog.

The easiest way to proceed is to read the application's .RES file with the Dialog Editor by loading it into the editor and at the same time retrieve the dialog symbols by opening the appropriate .H file. You can then save all the dialog information in the Dialog Editor's own dedicated .RES, .DLG, and .H files.

If you save the dialogs under the name DIALOGS, you can then use DIALOGS.DLG as a guide for removing the appropriate resource script statements from the .RC file and substituting a DIALOGS.DLG include statement. In the same way, remove the dialog symbols from the original .H file and include DIALOGS.H in your application and .RC file.

You could continue to let the dialog symbols reside in the original .H file by clicking Set Include on the File menu to associate that file with the dialogs. However, it will be easier for you if you take the time to put the dialog symbols in their own file. Then if you later want to archive the dialogs, examine the dialog files, or move the dialogs to another environment, all the information will be readily available to you.


Font Editor

With the Font Editor (FONTEDIT.EXE), you can modify existing fonts to create new fonts to use in your applications. You can use the Font Editor to create raster fonts. The Font Editor cannot create vector or TrueType fonts.

The Font Editor can do the following:

  • Edit letters, numbers, and other characters in a font.
  • Modify the height, width, and character-mapping of a font.
  • Change information in the font header.

For more information, see the help file FONTEDIT.HLP, included with the Font Editor.

Using Font Editor

To create a new font file with the Font Editor, you must open a preexisting font file. The font file ARTM1111.FNT is supplied with the Font Editor. After you open a font, the Font Editor displays the following features:

Feature | Description
Character window | Displays a copy of the character you want to edit.
Character-viewing window | Displays two instances of the character in its normal size, so you can examine the effects of your edits.
Character information | Displays the character value, and the character width and height, in pixels.
Font-viewing window | Displays normal-size copies of the characters in the font.

You can edit a font in the following ways:

  • By turning individual pixels in a character on and off
  • By adding and deleting columns or rows of pixels in a character.
  • By changing the width of a character in a variable-pitch font.
  • Changing the height of the font characters.
  • Changing the maximum width of a variable-pitch font.
  • Changing the character width of a fixed-pitch font.
  • Changing a font from fixed-pitch to variable-pitch.
  • Changing the weight of the font.
  • Changing the font-file header information. This header includes information such as the filename, typeface name, and copyright, as well as the font metrics.

After you create a new font with the Font Editor, you can use it in one of the following ways:

  • Add the font to your application's resource-definition file using the FONT Resource statement. Build the font resource into your application.
  • Create a new resource-definition file and add the font using the FONT Resource statement. Build a resource-only DLL that contains the font. Use an .FON extension instead of a .DLL extension.

Your application can install the font by calling the AddFontResource function. To remove a font, use the RemoveFontResource function.


Image Editor

With the Image Editor (IMAGEDIT.EXE), you can create graphical images to represent files, windows, cursors, and other objects in your Windows applications. The Image Editor provides you with a set of drawing tools for creating commonly used shapes.

The Image Editor can create the following types of images:

  • Bitmaps, which are graphical objects used to create, manipulate, and store images.
  • Cursors, which represent the position of a pointing device, such as a mouse.
  • Icons, which represent objects such as files, folders, shortcuts, applications, and documents.

For more information, see the help file IMAGEDIT.HLP, included with the Image Editor.


Using the Image Editor

Before creating a new image, you first need to design it. After you have a design, follow these steps to create the image:

To Create An Image

  1. Click New on the File menu. The Resource Type dialog box appears.
  2. Select either Bitmap, Cursor, or Icon, depending on the image type.
  3. For bitmaps, set the width, height, and colors. For cursors and icons, select the target device.
  4. Select colors from the palette, and drawing tools from the tool box.
  5. Draw the image in the drawing area with the selected tools.
  6. Save the file and exit the Image Editor.


Including Images in an Application

When you save an image, the Image Editor creates one of three files, depending on the image type, as follows:

  • A .BMP (bitmap) file. This file can be specified in resource-definition files with the BITMAP Resource statement. You can open this file programmatically with the LoadImage or LoadBitmap function.
  • A .CUR (cursor) file. This file can be specified in resource-definition files with the CURSOR Resource statement. It can contain more than one image. You can open this file programmatically with the LoadImage or LoadCursorFromFile function.
  • A .ICO (icon) file. This file can be specified in resource-definition files with the ICON Resource statement. It can contain more than one image. You can open this file programmatically using the LoadImage or LoadIcon function.


Hotspot Editor

A segmented hypergraphic is a graphic that has embedded hyperlinks that users click to initiate an action such as a jump to another help topic. Use the Hotspot Editor (SHED.EXE) to create segmented hypergraphic files to add to Windows help files.

For more information, see the help file SHED.HLP, included with SHED.

Using the Hotspot Editor

To create a segmented hypergraphic, follow these steps:

Creating a Segmented Hypergraphic

  1. Load an existing graphic from a file (.BMP, .DIB, or .WMF) or paste the graphic from the clipboard.
  2. Move the mouse to the position for the hotspot. Create the hotspot by holding down the mouse button and dragging the bounding rectangle until the hotspot is as large as desired.
  3. Save the file in .SHG format.

You can also specify attributes for each hotspot. Click Attributes on the Edit menu. You can set the following attributes:

  • Link type (jump, pop-up, or macro)
  • Context string (or macro, if the link type is a macro)
  • Visible or invisible hotspot borders
  • Hotspot identifier
  • Coordinates

To include a segmented hypergraphic in a help topic, use the bmc, bml, and bmr statements. These statements insert the graphic into the help file at the specified position. The syntax is as follows:

{bXmc filename.shg}{bXml filename.shg}{bXmr filename.shg}

Hotspots must reference valid context strings. The help compiler displays a warning if the hyperlink references a nonexistent context string.


CPU Stress Utility

Windows NT/Windows 2000

The CPU Stress utility (CPUSTRES.EXE) is useful for demonstrating the effects of priority levels on system performance. It can also be used to load the processor, so you can test your application when the system is under a heavy load.

To use CPUSTRES, run CPUSTRES.EXE. The CPU Stress dialog box that appears contains the following fields.

Field | Description |
Process Priority Class | Select Normal or High. |
Access Shared Memory | Click the check box and specify the size of the shared memory, in kilobytes. |
ThreadX | The X is a value from 1 to 4. Each thread has the following properties: |
 | Active | Mark the check box to activate the thread. To deactivate the thread, remove the mark.
 | Thread Priority | Click Idle, Lowest, Below Normal, Normal, Above Normal, Highest, or Time Critical.
 | Activity | Click Low, Medium, or Busy.


PfMon

Windows NT/Windows 2000

PFMon displays the faults that occur while executing a process. PFMon can start the application for you or attach to a running process.

The following is the PFMon command-line syntax:

pfmon [options] [AppCommandLine]
-?
Display the command-line syntax.
-n
Do not display running faults; log faults to PFMON.LOG.
-l
Log faults to PFMON.LOG.
-c
Only show code faults.
-h
Only show hard faults.
-p pid
Attach to the process with process identifier pid. Note that once PFMon is attached to the process, terminating PFMon will also terminate the process.
-d
Use tab-delimited database format.
-k
Show kernel mode page faults and user mode page faults.
-K
Show kernel mode page faults.
AppCommandLine
The command line of the application to monitor. Do not specify AppCommandLine if you are using -p pid.

When you terminate the application specified by AppCommandLine, PFMon prints a summary of the faults that occurred while executing the application. For example, execute the following command:

pfmon wperf

The summary printed when you terminate WPERF will look something like this:

wperf.dbg Caused     44 faults had     5 Soft   24 Hard faulted VA's
ntdll.dbg Caused     99 faults had    63 Soft    4 Hard faulted VA's
kernel32.dbg Caused  46 faults had    29 Soft    4 Hard faulted VA's
gdi32.dbg Caused     17 faults had     9 Soft    3 Hard faulted VA's
user32.dbg Caused    29 faults had    21 Soft    6 Hard faulted VA's
advapi32.dbg Caused   7 faults had     2 Soft    8 Hard faulted VA's
rpcrt4.dbg Caused     4 faults had     1 Soft    3 Hard faulted VA's

Total Faults 246 (KM 135 UM 246 Soft 164, Hard 82, Code 123, Data 123)


Service Control Utility

Windows NT/Windows 2000

The Service Control utility (SC.EXE) is useful for testing and debugging your service program. SC implements calls to all of the service control functions. You can specify any function parameters through the command line. You can create batch files that call SC with various command lines to see how your service behaves with repeated starting and stopping.

SC also displays complete status information, including state, checkpoint number, and wait hint.

The following is the command-line syntax for SC:

sc [ServerName] Command ServiceName [OptionName= OptionValue…]
ServerName
Specifies the name of the server if you are running the commands on a remote computer. The name must start with two backslash characters. If you are running the commands on the local computer, do not supply this parameter.
Command
Specifies one of the following SC commands:
Command | Description
config | Changes the configuration of a service (persistent).
Continue | Sends a CONTINUE control request to a service.
Control | Sends a control to a service.
Create | Creates a service (adds it to the registry).
Delete | Deletes a service (from the registry).
EnumDepend | Enumerates service dependencies.
GetDisplayName | Gets the display name for a service.
GetKeyName | Gets the name of the registry key for a service.
Interrogate | Sends an INTERROGATE control request to a service.
Pause | Sends a PAUSE control request to a service.
Qc | Queries configuration for the service. For detailed information, see the reference section, "SC QC."
Query | Queries the status for a service, or enumerates the status for types of services. For detailed information, see the reference section, "SC QUERY."
Start | Starts a service.
Stop | Sends a STOP request to a service.

ServiceName
Specifies the name given to the service key in the registry. This is different from the display name that you see in the Service control panel application.
OptionName
The name of an optional command parameter. You can supply zero or more optional pairs of parameter names and values. For a list of available names, use the command sc command, where command is a valid command name, as listed for Command.
OptionValue
Specifies the value for the parameter named by OptionName. For a list of available values, use the command sc command, where command is a valid command name, as listed for Command.

To display help information for a command, use the following command-line syntax:

sc [Command]

where Command has the values listed previously. The exception is the Query command, which causes SC to list the status of all running services. For help on the Query command, use the command sc and type y at the prompt, "Would you like to see help for the QUERY command?'


Stress Utility

Windows 95/98

The Stress utility (STRESS.EXE) lets you allocate system resources to see how your application behaves under low-resource conditions. You can allocate resources such as global memory, USER and GDI heap memory, file handles, and disk space.


Microsoft Editor

The Microsoft Editor (MEP.EXE) is a console-based text editor that is specialized for editing code. It contains many built-in editing features. To customize MEP, you can use the initialization file, TOOLS.INI. You can also create editor extensions to add custom features to MEP.

This overview is not meant to be comprehensive. It discusses the following topics:

  • The MEP Command Line
  • The TOOLS.INI File
  • Basic Editing
  • Accessing the Help File
  • Support Programs
  • MEP Editing Function Reference

For more information, please see the MS-DOS help file, MEP.HLP, included with MEP.


The MEP Command Line

To start MEP, use the MEP command. The following line shows MEP command-line syntax:

MEP [-?] [-D] [-e commands] [-r] [-m mark] [[-t] file]...

The MEP command's parameters can include one or more of the following options:

-?
Displays a list of MEP command-line options.
-D
MEP does not read TOOLS.INI or the status file.
-e commands
MEP executes the specified commands on startup. The commands argument is the name of a function or macro, or a quoted string that follows the syntax rules for a macro definition.
-t file
The file is temporary and is not retained in the status file. You must precede each temporary file name with -t.
-r
MEP starts in no-edit mode. You cannot make changes to files.
-m mark
MEP starts at the specified mark or line number.

On startup, the status line displays the following:

  • The name of the file being edited.
  • The type of file (based on the extension).
  • The length of the files (in lines).
  • The position (row, column) of the cursor or the upper-left corner.

The status line can also display the following during editing:

Indicator | Description
modified | The file has been changed.
Insert | MEP is in insert mode.
No-Edit | The file cannot be changed at any time during the editing session.
RO-File | The file has the read-only attribute. The file can be modified, but must be saved under a different filename.
pseudo | The file is a pseudo file.
Arg [1] | You typed ALT+A to start a command.
Argument canceled | You recently canceled a command.
REC | You are recording a macro.


The TOOLS.INI File

The TOOLS.INI file is the initialization and customization file for MEP. MEP reads key assignments, switch settings, extensions, and macro definitions from this file on startup. Each section in the TOOLS.INI begins with a tag that specifies the base name of the executable file for the tool that will use the section. MEP recognizes only the sections tagged [MEP - name]. MEP looks for TOOLS.INI in the directory given by the INIT environment variable. If INIT is not defined, MEP looks in the current directory.

MEP also stores status information, such as cursor position, settings, and the list of files you have edited, in a file named MEP.TMP. Between sessions, MEP saves certain settings in MEP.TMP. Settings in this file override those in TOOLS.INI.

When you start MEP, it reads the TOOLS.INI file, loads editor extensions, and reads MEP.TMP. To suppress this sequence and start MEP with no default assignments and no retained status, specify the /D option.

Defining Sections

The statements in the TOOLS.INI file are divided into sections. Each section begins with a tag that indicates its use. The main section of TOOLS.INI that MEP uses has the [MEP] tag. You list most editor assignments and macro definitions in this section. When you save a key assignment, switch setting, or recorded macro, MEP puts the new definition in this section unless the definition belongs to a specific editor extension. Extensions use the following format for their tags:

[MEP - ExtensionName]

For example, help extension settings appear after the [MEP-MHELP] tag.

You can define named sections of TOOLS.INI that you load manually. Use named sections to make special key assignments, to load complex or rarely used macros, or to create alternate configurations. To load a named section of TOOLS.INI under the tag [MEP - name], execute the following command:

ALT+A name SHIFT+F8

This method of reading a tagged section can be used for any kind of tagged section, including the automatically loaded sections.

Specifying Comments

To specify a comment in the TOOLS.INI file, place a semicolon (;) at the beginning of a line or following a space. MEP ignores text from the semicolon to the end of the line.

For example, the first semicolon in the following statement is part of a command, and the second semicolon begins a comment.

Printcmd:lister -t4 %s -c;   ;Print using lister program

Semicolons inside a quoted string do not begin a comment.

Specifying Line Continuation

To continue a long macro definition on multiple lines in TOOLS.INI, use a backslash character (\). The backslash must be preceded by a space to be treated as a line-continuation character.

Precede the backslash by two spaces or a tab if you want the macro to contain a space at that location. The backslash must be the last character on the line except for spaces and tabs.

For example, the backslash in the following statement is not a line continuation.

Qreplace:CTRL+\

However, the backslash at the end of the first line in the following example is a line continuation.

Findtag:=arg arg "^\\[[^\\]]+\\]" psearch ->none  \
arg setwindow => :>none arg "no tag" message

In the second example, the backslash is preceded by two spaces. The first space is included to separate "->none" from "arg" in the macro definition. The second space identifies the backslash that follows it as the line-continuation character.

Switches

The following table gives an alphabetical listing of MEP switches, along with their types, defaults, and descriptions.

Switch | Type | Default | Description
askexit | Boolean | No | Prompts for confirmation on exit.
Askrtn | Boolean | Yes | Prompts for ENTER when returning from the command window.
autosave | Boolean | Yes | Saves the current file when you open another file.
backup | Text | bak | Specify none for no backup. Specify undel if the old file is to be moved to the DELETED directory. Specify bak to indicate that the old version of the file should be changed to filename.bak.
case | Boolean | No | Perform case-sensitive find and replace operations.
displaycursor | Boolean | No | Show the current cursor position on the status line. When the switch is off, the position given is that of the upper-left corner.
editreadonly | Boolean | Yes | Allows read-only files to be edited.
entab | Numeric | 1 | A value of 0 means tabs are not used to represent white space; 1 means all multiple spaces outside quoted strings are converted; 2 means all multiple spaces are converted to tabs.
enterinsmode | Boolean | No | Start MEP in insert mode rather than overstrike mode.
errcolor | Numeric | 04 | Specifies the color used for error messages.
errprompt | Boolean | Yes | Prompt for a keystroke at each error.
extmake | Numeric |  | Associates a command line with a particular file extension for use by the Compile function. The text is of the form extension commandline.
fgcolor | Numeric | 07 | Specifies the color used for the editing window.
filetab | Numeric | 8 | The number of spaces associated with each tab column. If entab > 0, this setting determines how spaces are converted to tabs.
height | Numeric | 23 | Specifies the number of lines in the editing window.
helpboldcolor | Numeric | 0F | Specifies the color of text designated as bold.
helpfiles | Text |  | Specifies online help (.HLP) file.
helpitalcolor | Numeric | 0A | Specifies the color of text designated as italic.
helpundcolor | Numeric | 0C | Specifies the color of text designated as underlined.
helpwarncolor | Numeric | 07 | Specifies the color of text used for warning notes.
helpwindow | Boolean | Yes | Specifies whether MEP splits the screen to display help.
hgcolor | Numeric | 02 | Specifies the color of text highlighted by the search command.
hike | Numeric | 4 | Specifies the new line position of the cursor when it is moved out of the current window by more than vscroll lines..
hscroll | Numeric | 10 | Specifies the number of columns shifted left or right when the cursor is scrolled out of the editing window.
infcolor | Numeric | 06 | Specifies the color used for informative text.
load | Text |  | Specifies the name of the executable file for an extension.
noise | Numeric | 50 | Specifies the number of lines counted at a time when searching or loading a file.
printcmd | Text |  | Specifies the system command executed for the Print command.
readonly | Text |  | Specifies the system command executed when overwriting a read-only file.
realtabs | Boolean | Yes | Preserves tab characters instead of converting them to spaces.
rmargin | Numeric | 72 | Specifies the right column margin used in word-wrap mode.
savescreen | Boolean | Yes | Saves and restores the console (used with Shell and Exit).
searchwrap | Boolean | No | Causes find and replace commands to wrap past the end of the file and continue searching at the beginning.
selcolor | Numeric | 70 | Specifies the color of text highlighted by an on-screen argument.
shortnames | Boolean | Yes | Allows you to load a file by giving only the base name. MEP searches the file list.
softcr | Boolean | Yes | Attempts to indent, based on the format of the surrounding text.
stacolor | Numeric | 03 | Specifies the color used for the status-line information.
tabalign | Boolean | No | When this switch is off, the cursor can be placed anywhere in a tab field. When on (and realtabs is on), the cursor must align with the column position of the tab.
tabdisp | Numeric | 32 | Specifies the ASCII value of the character used to display tabs.
tabstops | Numeric | 4 | Specifies the number of spaces between each logical tab stop for Tab and Backtab.
tmpsav | Numeric | 20 | Specifies the maximum number of recently edited files listed in MEP.TMP.
traildisp | Numeric | 0 | Specifies the ASCII value of the character used to display trailing spaces, if trailspace is on.
trailspace | Boolean | No | Preserves trailing spaces in each modified line.
undelcount | Numeric | No limit | Specifies the number of backup copies that are saved when backup is set to undel.
undocount | Numeric | 10 | Specifies the number of edit functions you can undo.
viewonly | Boolean | No | When set, no file can be edited.
vscroll | Numeric | 7 | Specifies the number of lines shifted up or down when the cursor is scrolled past the lines in the editing window.
wdcolor | Numeric | 07 | Specifies the color of the border line created when you split a window.
width | Numeric | 80 | Specifies the width of the display mode.
wordwrap | Boolean | No | Breaks lines of text when you edit them beyond the margin specified by rmargin.


Basic Editing

This topic discusses how to work with files in general. For a complete list of editing functions, see MEP Editing Function Reference.

MEP accepts two basic forms of commands:

  • function
  • ALT+A [argument] function

You can either type the argument or select characters by moving the cursor from its current position. After you begin entering a command, you can cancel it by pressing ESC. Note that some commands work differently when used with the meta prefix (F9).

The following table shows how to use some of the most common file operations:

Editing Task | Key
Exit editor after saving current file. | F8
Exit editor without saving current file. | F9+F8
Save current file without exiting. | ALT+A ALT+A F2
Save current file as filename without exiting. | ALT+A ALT+A filename F2
Load another file. | ALT+A filename F2
Copy another file into current file at cursor. | ALT+A ALT+A filename SHIFT+INS
Discard most recent changes and reread the file from disk. | SHIFT+F7

The following table shows how to move through a file.

Editing Task | Key
Move a single character. | DirectionKey
Move to beginning of line. | HOME
Move to end of line. | END
Move up a page. | PGUP
Move down a page. | PGDN
Move to the top of the screen. | F9+UP
Move to the bottom of the screen. | F9+DOWN
Move to the top of the file. | CTRL+UP
Move to the bottom of the file. | CTRL+DOWN
Move to the next word. | CTRL+RIGHT
Move to the previous word. | CTRL+LEFT

The following table shows some of the most common ways to edit text.

Editing Task | Key
Change to insert mode. | INS
Insert a blank line (insert mode). | ENTER
Insert a blank line (overstrike mode). | CTRL+N
Select text. | ALT+A DirectionKey
Remove text. | DEL
Remove text from cursor to end of the line. | ALT+A DEL
Remove line or selection. | CTRL+Y
Copy text. | ALT+A CursorMovement CTRL+INS
Paste text. | SHIFT+INS
Move text. | DEL CursorMovement SHIFT+INS
Find text. | ALT+A text F3
Find and replace text. | CTRL+L argument argument (prompts for the search string, then the replace string)


Accessing the Help File

Before you can open the help file, you must ensure that the help system has been configured properly.

To Verify the Help Configuration

  • Check that MEP.HLP is located in a directory specified by the PATH environment variable.
  • Check that the TOOLS.INI file is located in the directory specified by the INIT environment variable.
  • Check that the TOOLS.INI file contains the following lines:
    [mep-mhelp]
helpfiles: mep.hlp

[mep]
load: mhelp.dll

The following table gives the keystrokes for the most common help tasks.

Help Task | Key
Go to the help contents. | ALT+A contents F1
Get help for the word at the cursor. | F1
Get help for a specific topic. | ALT+A topic F1
Get previously viewed help. | ALT+F1
Get the next topic in the help file. | CTRL+F1
Move to the next hotspot. | TAB
Move to the previous hotspot. | SHIFT+TAB
Get help for the highlighted hotspot. | ENTER
Move between windows. | F6
Exit split-window help. | ESC
Exit help and return to previous file. | F2


Support Programs

There are three programs that work in conjunction with the Microsoft Editor:

  • UNDEL.EXE
  • EXP.EXE
  • RM.EXE

These programs work with backup files. When a file is updated and the backup switch is set to undel, the old version of the file is copied to a hidden subdirectory called DELETED. The UNDEL.EXE and EXP.EXE programs manipulate the files in the DELETED subdirectory.

Use UNDEL.EXE to move a file from the DELETED subdirectory to the parent directory. Its command-line syntax is as follows:

undel [filename]

If you do not specify filename, the contents of the DELETED subdirectory are listed. If there is more than one version of the file, you are given a list from which to choose. If the file already exists in the parent directory, the two files are swapped.

Use EXP.EXE to remove all of the files in the hidden DELETED subdirectory of the specified directory. Use the following command-line syntax:

exp [/r] [/q] [directory]

If you do not specify directory, the DELETED subdirectory of the current directory is used. If you specify the /r option, EXP.EXE recursively operates on all subdirectories. The /q option specifies quiet mode; the deleted file names are not displayed on the screen.

Use RM.EXE to move a file to the hidden DELETED subdirectory of the directory containing the file. Use the following command-line syntax:

rm [options] [files]

Where files is a list of files to be moved and options can be one or more of the following:

/d
Delay until next reboot.
/f
Deletes read-only files without prompting.
/i
Inquires for permission before removing files.
/k
Keeps read-only files without prompting.
/r directory
Recurses into subdirectories of the specified directory.
/t
Take ownership of the file if the delete fails.
/x
Do not save deleted files in DELETED subdirectory.


MEP Editing Function Reference

MEP supports the following categories of functions used for editing.

  • Command Manipulation
  • File Operations
  • Cursor Movement
  • Mark/Goto Position
  • Window
  • Searching/Replacing
  • Special Insert
  • Inserting/Deleting Text
  • Programming
  • Miscellaneous


Command Manipulation

Description | Function | Key
Begin a function argument. | Arg | ALT+A
Turn on the meta command prefix. | Meta | F9
Cancel current argument. | Cancel | ESC
Recall the last selection. | Lastselect | CTRL+U
Recall the last text argument. | Lasttext | CTRL+O
Type the next character literally. | Quote | CTRL+P
Reverse the last edit. | Undo | ALT+BKSP
Toggle between box and stream mode. | Boxstream | CTRL+B
Assign a key or define a macro. | Assign | ALT+=
Execute command or macro list. | Execute | ALT+E
Toggle macro recording. | Record | unassigned
Display key or macro assignment. | Tell | CTRL+T
Display or clear status bar. | Message | unassigned


File Operations

Description | Function | Key
Save the file or open a new file. | Setfile | F2
Reread the file, discarding edits. | Refresh | SHIFT+F7
Merge a file or program output. | Paste | SHIFT+INS
Print all or part of file. | Print | CTRL+F8
Save all modified files. | Saveall | unassigned
Exit with or without saving. | Exit | ALT+X
Toggle no-edit state of file. | Noedit | unassigned


Cursor Movement

Description | Function | Key
Move left one character. | Left | CTRL+S
Move right one character. | Right | CTRL+D
Move up one line. | Up | CTRL+E
Move down one line. | Down | CTRL+X
Move to beginning of next line. | Newline | unassigned
Move to first character in line. | Begline | unassigned
Move past last character in line. | Endline | END
Move left one tab stop. | Backtab | SHIFT+TAB
Move right one tab stop. | Tab | TAB
Move back by paragraphs. | Mpara | CTRL+UP
Move forward by paragraphs. | Ppara | CTRL+DOWN
Move back by words. | Mword | CTRL+LEFT
Move forward by words. | Pword | CTRL+RIGHT
Move back by pages. | Mpage | CTRL+R
Move forward by pages. | Ppage | CTRL+C
Move to upper-left corner. | Home | unassigned
Move to top of file. | Begfile | CTRL+PGUP
Move to end of file. | Endfile | CTRL+PGDN


Mark/Goto Position

Description | Function | Key
Define or move to mark. | Mark | CTRL+M
Go to a specific line number. | Mark | ALT+A line CTRL+M
Restore saved cursor position. | Restcur | unassigned
Save cursor position. | Savecur | unassigned


Window

Description | Function | Key
Moves the cursor to the next window. | Window | F6
Split the active window horizontally. | Arg Window | ALT+A F6
Split the active window vertically. | Arg Arg Window | ALT+A ALT+A F6
Close the active window. | Meta Window | F9 F6


Searching/Replacing

Description | Function | Key
Search forward. | Psearch | F3
Search backward. | Msearch | F4
Highlight all matching strings. | Searchall | SHIFT+F6
Replace with confirmation. | Qreplace | CTRL+\
Replace without confirmation. | Replace | CTRL+L
Search a list of files. | Mgrep | unassigned
Replace over a list of files. | Mreplace | unassigned


Special Insert

Description | Function | Key
Insert current date. | Curdate | unassigned
Insert current day. | Curday | unassigned
Insert current time. | Curtime | unassigned
Insert name of current file. | Curfile | unassigned
Insert extension of current file. | Curfileext | unassigned
Insert base name of current file. | Curfilenam | unassigned
Set or insert environment variables. | Environment | unassigned


Inserting/Deleting Text

Description | Function | Key
Copy line or selection to the clipboard. | Copy | CTRL+INS
Insert text from the clipboard. | Paste | SHIFT+INS
Start new line, breaking current line. | Emacsnewl | SHIFT+ENTER
Delete selection. | Delete | unassigned
Delete box or lines. | Ldelete | CTRL+Y
Delete stream of text. | Sdelete | SHIFT+DEL
Delete character to left, no line breaks. | Cdelete | CTRL+G
Delete character to left, with line break. | Emacscdel | BKSP
Insert spaces into selection. | Insert | unassigned
Insert spaces in box or lines. | Linsert | CTRL+N
Insert spaces into stream selection. | Sinsert | CTRL+J


Programming

Description | Function | Key
Compile or spawn a command. | Compile | SHIFT+F3
Go to next message. | Nextmsg | unassigned
Balance parentheses and brackets. | Pbal | CTRL+[


Miscellaneous

Description | Function | Key
Displays list of previously edited files. | Information | SHIFT+F10
Rereads initialization file. | Initialize | SHIFT+F8
Toggles insert mode on and off. | Insertmode | INS
Spawns a system-level command line. | Shell | SHIFT+F9


Managing Files

The Platform SDK includes several utilities that are useful for managing files. This overview covers the following topics:

  • Comparing Files Using WINDIFF
  • Finding Files Using WHERE
  • Searching Files Using QGREP


Comparing Files Using WINDIFF

To compare files and display the results graphically, use WINDIFF.EXE. The following line shows WINDIFF command-line syntax:

windiff [path1] [path2]

where path1 and path2 indicate the files to be compared. WINDIFF uses the following rules to determine what is to be compared:

  • If you invoke WINDIFF without specifying path1 or path2, you can click Compare Files or Compare Directories from the File menu to specify the files to compare.
  • If you invoke WINDIFF with a filename for path1, but nothing for path2, WINDIFF compares the file with a file of the same name in the current directory.
  • If you invoke WINDIFF with a directory name for path1, but nothing for path2, WINDIFF compares the files in the specified directory with the files in the current directory.
  • If you invoke WINDIFF specifying files for path1 and path2, WINDIFF compares the two files.
  • If you invoke WINDIFF specifying directories for path1 and path2, WINDIFF compares the files in those directories.

The results are initially displayed in outline mode. WINDIFF lists the files that were compared and indicates whether they are identical or whether one file is newer than the other. To view the differences in expanded mode, select the file from the display and click the Expand button. The parts that are common to both files are displayed on a white background. The parts that belong to the file listed on the left are displayed on a red background. The parts that belong to the file listed on the right are displayed on a yellow background. To return to outline mode, click the Outline button.

For more information, see the help file WINDIFF.HLP, included with WINDIFF.


Finding Files Using WHERE

To locate a file or directory on your local computer or a remote computer, use WHERE.EXE. The following line shows WHERE command-line syntax:

where [/r dir] [/qte] pattern
/r dir
Perform a recursive search, starting with directory dir. If you do not specify dir, where will search the directories specified by the PATH environment variable.
/q
Quiet mode (use exit code to determine the result).
/t
Display size and time.
/e
Display the .EXE type.
pattern
The name of the file or directory to locate, which can include wildcard characters (* and ?).

For example, the following command will find all occurrences of FileName on the PATH:

where FileName

The following command will find all occurrences of FileName, searching recursively from the current directory:

where /r . FileName

The following command will find all occurrences of FileName on the specified network share:

where /r \\ServerName\ShareName FileName


Searching Files Using QGREP

To locate text within a file or group of files, use QGREP.EXE. The following line shows QGREP command-line syntax:

qgrep [-?BELOXlnzvxy] [-e string] [-f file] [-i file] [strings] [files]
-?
Print command-line syntax.
-B
Match pattern at beginning of line.
-E
Match pattern at end of line.
-L
Treat search strings literally.
-O
Print seek offset before each matching line.
-X
Treat search strings as regular expressions.
-l
Print only the filename if the file contains a match.
-n
Print line numbers before each matching line.
-z
Print matching lines in MSC error message format.
-v
Print only lines that do not contain a match.
-x
Print lines that match exactly.
-y
Treat upper- and lower-case as equivalent.
-e string
Treat the next argument as a literal search string.
-f file
Read search strings from file.
-i file
Read file list from file.
strings
The search string(s). White spaces separate search strings, unless the argument is prefixed with -e.
files
The file(s) to search, which can include wildcard characters (* and ?).

For example, the following command finds either arg1 or arg2 in FileName:

qgrep "arg1 arg2" FileName

The following command finds arg1 arg2 in FileName:

qgrep -e "arg1 arg2" FileName


Improving Application Performance

This overview provides some guidelines and hints to help you improve application performance on Windows NT/Windows 2000.

The sophisticated virtual memory manager in Windows NT/Windows 2000 permits applications to have direct access to very large data structures. Increased protection permits applications to be less concerned about cooperating with other applications, and more focused on being responsive to the user. However, there are costs associated with increased protection and portability to multiple processors that require some changes to the coding styles you used with earlier versions of Windows.

Both Windows NT/Windows 2000 and Windows 95/98 implement the Win32 API. If your application must run on both platforms, you must be careful that design decisions that improve performance on one platform do not seriously degrade performance on the other platform.


Managing Kernel Resources

The following sections discuss using kernel resources effectively to improve performance.

  • Managing Memory
  • Managing File Operations
  • Managing Processes


Managing Memory

Windows NT/Windows 2000 can address 4 gigabytes of memory. Each application running on this system has most of the lower 2 gigabytes of its virtual address space at its disposal. For a console application, the system uses 5.5 MB of the lower 2 gigabytes to permit you to view portions of the system that reside elsewhere. For a Windows application, the system uses to 9 MB for that purpose.

If your application is being ported from another operating system or from an 16-bit Windows, you might have developed a special virtual memory scheme for your own private use. Having another memory manager for your application decreases performance. To increase performance, let the system manage the virtual address space.

Consider using file mapping in the following situations.

  • You are randomly accessing a read-only file or a file that is only written to by one process. Shared writing to memory-mapped files from multiple processes requires a bit of internal system synchronization and does not work well if the file is remote, because you will have to manage the remote synchronization. Using memory-mapped files for sequential file access is faster than standard sequential file access, but uses more memory than the file system cache does. If you are going to access a file sequentially, use the FILE_FLAG_SEQUENTIAL_SCAN flag when calling the CreateFile function.
  • You are using a temporary file and you know its maximum size. You can map a large temporary space which is backed by the system paging files instead of by an existing file. Simply pass INVALID_HANDLE_VALUE as the file handle to the CreateFileMapping function and specify the size you need. You can also call the VirtualAlloc function to create a large data space backed by the paging file, but this memory is not sharable with another process. However, do not create a large area backed by disk if your application must run on computers with limited disk space. Instead, use VirtualAlloc to reserve that amount of linear address space, then commit pages as you need them.
  • You are managing communication between multiple processes. Memory-mapped files are faster than other mechanisms, such as named pipes, RPC, or shared file access. You might need a mutex to protect access to the shared section, but mutex operations are inexpensive.


Managing File Operations

  • If you are processing a file sequentially, use a page at a time to reduce the number of calls you have to make to the file system. If you are randomly accessing small amounts of data, you may wish to use memory-mapped files.
  • In MS-DOS-based systems, there is a limit on the number of files the system can have open at one time. Therefore, many applications open and close files frequently. Because of the additional protection and security in Windows NT/Windows 2000, opening a file uses more resources. Therefore, on Windows NT/Windows 2000, open files when you first need them, and close them when you are finished with them. The number of files you can open is limited only by the amount of non-paged pool in the system. The system stores information for all open objects in non-paged pool.


Managing Processes

  • Using multiple threads to improve performance, especially from server applications or computers with multiple processors. You can also use multiple threads to allow your application to be more responsive to user input. As an alternative, Windows NT/Windows 2000 supports asynchronous file access. You can issue file requests and have the system notify you when they have completed. This is more efficient than having a separate thread for each outstanding concurrent file request.
  • Use the SetPriorityClass function to allow your process to use the real-time priority class. This is useful for an application which is processing data in real time or doing time-sensitive communication with an external device. Your application should not use the real-time priority class for very long or you it will preempt all activity on the system, including the work of system processes.
  • Call the VirtualLock function to identify a small number of pages to retain in memory, so you do not have to wait for normal paging when attempting to respond to a real-time device. Your design should minimizes the amount of code that executes in the real-time priority class with locked pages. You can use event objects and memory-mapped files to exchange information with processes running at normal priority.
  • When storing and retrieving data from the registry, use the data type MULTI_SZ. This data type allows you to store a set of data values under the name of a single value by concatenating the strings into a single multistring. A multistring has multiple individual strings separated by a /0 character, with the last one followed by an additional /0 character. One registry call retrieves all the strings. This is very efficient, especially if the value is accessed remotely.
  • Windows NT/Windows 2000 uses Unicode internally. Unicode is a 16-bit character-coding standard which includes symbols for all international languages. From a performance viewpoint, it is better to write the application to work with Unicode. This decreases overhead and make the application easier to port to foreign languages.


Managing Graphics

Whenever possible be sure to use PolyTextOut, PolyPolyline, PolylineTo, PolyDraw, PolyBezier, and PolyBezierTo functions. These functions exploit the fact that many drawing calls use identical attributes, and so multiple items can be drawn in a single call once the brushes, pens, colors, and fonts have been selected. For example, the console window uses PolyTextOut. This change significantly reduces scrolling time in a console window.

If you are writing an application that draws on the display, then the CreateDIBSection function can improve performance. This function allows you to share a memory section directly with the system, and thus avoid having it copied from your process to the system each time there is a change. Previously, a common practice was to call the GetDIBits function, make the required changes, then call the SetDIBits function. These steps were often repeated on different scan lines of the bitmap before the image was ready for updating. Using CreateDIBSection is much simpler.

One word of caution if you decide to use CreateDIBSection. You need to be sure that any calls that might affect your bitmap have completed before you start to draw in it. This is because the batching of GDI calls may cause their delayed execution. For example, suppose you make a PatBlt call to clear your bitmap, then you start to change the bits in your DIB section. If the PatBlt call was batched, it might not actually execute until after you start to make the bitmap changes. So, before you make changes to your DIB section, be sure to call GdiFlush if you have made changes to the bitmap with earlier GDI calls.


Batch Processing for Graphics

GDI calls are handled using batch processing. Each thread has a batch limit. The GDI calls for a thread are not sent until the batch limit is reached or until the thread calls a function which flushes the batch. To increase performance, make sure that the batch limit is as large as appropriate and that your code is structured to minimize flushing the batch.

Three function calls help you manage the batching of GDI calls. The GdiSetBatchLimit function allows you to raise and lower the batch limit, which defaults to ten. For best performance, you should set the limit as high as possible while avoiding jerky drawing on the display. You will want to test any changes to the batch limit on a very slow computer and a very fast one to be sure you have not introduced a problem which will only appear in one environment or the other. You can call GdiGetBatchLimit to determine the current limit. Finally, you can call GdiFlush to flush the batch at the end of an operation you would like to see displayed immediately.

In general, you can batch graphical output functions that return a Boolean value, indicating success or failure. A few frequently used functions that return non-Boolean results which were seldom used have new replacement calls that just return Boolean results. The SetPixelV and MoveToEx functions are two important cases.

Most calls that manipulate the window system flush the batch. One reason is that much of the window system is visible to all processes on the desktop and so the central data repository. The PeekMessage function does not flush the batch, but the GetMessage function does. Graphics calls that return a handle or a number flush the batch. An important exception to this is the group of calls for selecting fonts, brushes, and pens. These calls are batched. However, selecting bitmaps and regions flush the batch. So do the SetWorldTransform and SetMapMode functions. When possible, you should organize your code so that GDI calls that do not flush the batch are grouped together, then make the calls that flush the batch.

There are circumstances in which you will want to minimize the batching of GDI calls. For example, when you need the display to immediately reflect the drawing you do, you want to flush the batch explicitly no matter how large or small it is. Failing to do this causes the data to be updated with noticeably odd timing. Also, you want to minimize the batch when you are debugging your application. Otherwise, an error returned in the middle of a batch may not be received until some other call flushes the batch; it will appear then that the wrong call failed. Finally, if you are obtaining certain performance measurements on your application, you will want to set the batch to one.


Managing the Device Context

In 16-bit Windows, it was important to conserve the use of drawing objects. In Windows NT/Windows 2000, there are richer data structures to hold a new wealth of data. That can mean it takes longer to look things up.

The old limitations gave rise to a coding style in which you created, selected, used, and destroyed objects (like pens and brushes) constantly. This limited the number of objects in the system and kept the application from running into the limits of the address space. Because of the transition to a client-server architecture in Windows NT/Windows 2000, object creation and destruction are more expensive. Because of the new capacity for large numbers of objects, selecting objects is also a bit slower. For example, the old coding style

select(grey);
patblt(...);
select(black);
patblt(...);
select(grey);
patblt(...);
select(black);
patblt(...);

is slower on Windows NT/Windows 2000 than

select(grey);
patblt(...);
patblt(...);
patblt(...);
select(black);
patblt(...);
patblt(...);
patblt(...);

In Windows NT/Windows 2000, create all your objects when you first need them. Do not destroy the objects until you are done with them.

If you were programming for 16-bit Windows, you were told to avoid the use of your own DC's because the system could only support a few. This is not true on Windows NT/Windows 2000. Use the creation style CS_OWNDC as much as you can when you call the RegisterClass function. This avoids repeated calling of the relatively expensive GetDC and ReleaseDC functions every time you have to draw. It also preserves the selected objects in your own DC in between calls, eliminating the need to select them again after each call to GetDC.


Managing Asynchronous Input

One of the biggest difference between 16-bit Windows and Windows NT/Windows 2000 is the input model. On 16-bit Windows, there is an synchronous input model, sometimes called cooperative multitasking. In this model, each application must process its messages, otherwise, it would hold up all the other applications on the system. A common coding style involved frequently calling the PeekMessage function, because every application constantly had to check the message queue for messages and pass them on. If they did not, the system would appear to hang.

On Windows NT/Windows 2000, there is an asynchronous input model. In this model, messages are sent only to the processes that need to see them. If one process ceases to deal with its messages, it may become unresponsive and cease to update its display area, but the rest of the system is not affected. This means that PeekMessage need only be called to remain responsive to the user during a lengthy operation.


Considerations for RISC Computers

Once you write an application for the x86 version of Windows NT/Windows 2000, it is easy it is to get it to run on RISC versions of Windows NT/Windows 2000. This is because there are virtually no processor dependencies in the Win32 API.

However, an application's performance can suffer on a RISC computer if its data is not properly aligned. To handle this problem, align the data in your source for both RISC and non-RISC computers. You want to assure that you have DWORD values on DWORD boundaries, and LARGE_INTEGER values on 8-byte boundaries.

Normally the compiler makes sure that data is correctly aligned. However, data structures from a file or from over a network may not follow alignment rules. With the Microsoft® Visual C++® compiler, you will want to use the PACK and UNPACK pragmas to define these structures, and the modifier UNALIGNED to declare pointers to them. If you do not do this, you get alignment faults. On some systems, these simply generate traps, and you can fix your program. However, some systems handle your unaligned references with a trap handler. This slows down your application and can be difficult to track down.


Using PView

The PView process viewer lets you examine and modify many characteristics of processes and threads running on your Microsoft® Windows NT®/Windows® 2000 system.

PView can help you answer questions like these:

  • What are the process identifiers (PID) of the running processes?
  • How much memory does the program allocate at various points in its execution, and how much memory is being paged out?
  • Which processes and threads are using the most CPU time?
  • How does the program run at different system priorities?
  • What happens if a thread or process stops responding to DDE, OLE, or pipe I/O?
  • What percentage of time is being spent running API calls?

For more information, see the following topics:

  • PView Main Dialog Box
  • Memory Details Dialog Box

Warning PView lets you modify the status of processes running on your system. As a result, by using PView, you can stop processes and potentially halt the entire system. Make sure that you have saved edited files before running PView.


PView Main Dialog Box

The main PView dialog box (see the following figure) consists of several fields containing information on active processes and threads, and controls to change their behavior.

The following table describes the buttons that control PView.

Button | Description
Exit | Closes Pview.
Memory Details | Opens the Memory Details dialog box.
Kill Process | Removes the highlighted process from the system. This is different from choosing Close from the system menu, because the process is not informed of the shutdown (with WM_DESTROY) before it is stopped.
Refresh | Updates information in the main PView dialog box and the Memory Details dialog box.
Connect | View information about the computer specified in the Computer field. The Computer field should contain the network name of the computer that you wish to view. Your ability to connect to a remote system may be affected by security on the target computer.

For more information on the other fields, see the following topics:

  • Process Selection
  • Process Memory Used
  • Priority
  • Thread Selection
  • Thread Information
  • Thread Priority


Process Selection

The Process Selection field displays information on the accessible processes running on the system. From this list, you can select a process to use for future actions. All other information and control areas in PView reflect the process chosen in this field.

Note Because Windows NT/Windows 2000 is a secure operating system, you may not be able to view or alter attributes of some programs running on the system.

The items in the Process Selection field are as follows.

Item | Description
Process | Name of the process. The PID is included in parentheses.
Processor Time | Amount of CPU time that this process has used.
Privileged | Percentage of the CPU time that was spent executing privileged code (code in the NT kernel).
User | Percentage of the CPU time that was spent executing user-mode code. This time includes time running protected subsystem code.


Process Memory Used

The Process Memory Used field displays information on the memory usage of the process selected in the Process Selection field.

The items in the Process Memory Used field are as follows.

Item | Description
Working Set | The average amount of physical memory used by the process. The longer a process has been running, the more accurate this value is.
Heap Usage | The current total heap being used by the process. Heap space is taken by dynamically allocated data, including memory reserved by LocalAlloc, HeapAlloc, VirtualAlloc, and GlobalAlloc.


Priority

The Priority buttons allow you change the base priority of the process highlighted in the Process Selection field. This priority determines the activity of all threads of the selected process.

The priorities used are as follows.

Priority | Description
Very High | Maximum priority. CPU time is split between this and other Very High priority processes. Lower priority processes will execute only when all Very High priority processes are blocked.
Normal | The standard-priority group, also known as "foreground." Most applications run with normal priority.
Idle | The lowest-priority group, also known as "background." Processes with this priority will execute only when the system has no higher-priority processes that need CPU time. Screen savers run at this priority.


Thread Selection

The Thread Selection field displays statistics for threads of the process selected in the Process Selection field and lets you select a thread for further operations.

The items in the Thread Selection field are as follows.

Item | Description
Thread(s) | The thread ID number. This is the handle returned by CreateThread.
Processor Time | The amount of time that this instance of the thread has been running.
Privileged | The percentage of the CPU time that was spent executing privileged code (code in the NT kernel).
User | The percentage of the CPU time that was spent executing user code. This time includes time running protected subsystem code.


Thread Information

The Thread Information field displays execution information about the thread selected in the Thread Selection field.

The items in the Thread Information field are as follows:

Item | Description
User PC Value | The value of the instruction pointer for this thread.
Start Address | The address of the entry point of this thread. This information is useful for debugging.
Context Switches | Number of times that this thread has received CPU attention.
Dynamic Priority | The current dynamic thread priority. This number is determined by many factors, including user activity.


Thread Priority

The Thread Priority field shows you the base priority of the thread selected in the Thread Selection field. This is not an absolute priority, but is a range of priorities that can be selected by the operating system for the selected thread.

The items in the Thread Priority field are as follows.

Item | Description
Highest | The highest priority level allowed by the process priority.
Above Normal | Slightly elevated priority.
Normal | The standard priority level for the given process priority.
Below Normal | Reduced priority.
Idle | No CPU time will be spent on this thread unless all other threads are blocked.


Memory Details Dialog Box

The Memory Details dialog box (see the following figure) gives information on the process selected by the Process Selection box in the main PView dialog box. To update the information contained in this dialog box, return to the main dialog box and click on the Refresh button.

This dialog box consists of the following fields.

Field | Description
Process | The name and process ID of the process selected in the Process Selection box of the main dialog.
User Address Space | Displays statistics for specific .EXE or .DLL files or "Total Commit," which displays statistics for all components of the currently selected process.
Mapped Commit | Consists of pagefile-backed shared memory regions.
Private Commit | Consists of writeable pages that are not shared; they are private to that process, usually created with LocalAlloc or VirtualAlloc.
Virtual Memory Counts | Displays statistics on Virtual Memory usage.

The statistics used are the following.

Statistic | Description
Inaccessible | Address space that cannot be accessed. This includes memory reserved by VirtualAlloc.
Read Only | Read-only data and code.
Writeable | Total data address space that can be written to.
Writeable (Not Written) | Data address space that can be written to, but has not been.
Executable | Code in selected EXEs and DLLs.
Working Set | Average amount of virtual memory used by the process. The longer a process has been running, the more accurate this value is.
Peak Working Set | Maximum value attained by the Working Set described above.
Private Pages | Number of pages marked as private.
Virtual Size | Current size of virtual memory for this process.
Peak Virtual Size | Maximum size of virtual memory for this process.
Fault Count | Number of page faults. Each page fault represents an attempt to access memory at an address that was not in physical memory.


Performance Tuning Win32-based Applications

After your application is complete, you can focus on improving its performance on Windows NT/Windows 2000. Even if you are completely familiar with the design and implementation of the application code, you will need tools for performance tuning.

This overview briefly discusses the tools you can use to help you find performance problems in your application. To provide an example, this overview describes how several of these tools were used to find a performance problem in the Solitaire game.

These tools are flexible and can address a wide variety of performance issues. The tools discussed are:

  • Performance monitor
  • Call attributed profiler (CAP)
  • APIMon
  • Profile


Performance Monitor

When you notice that you have a performance problem, your first step should be to run Performance Monitor. It is not the objective of Performance Monitor to solve all performance problems, but rather to identify the areas in which performance problems exist. Isolating the problem is a good first step. The Platform SDK provides several tools you can use to tune your application, so running Performance Monitor before tuning helps to ensure that you use the right tools to isolate the problem.

The performance data is charted in the following window.

Choose the performance counters to monitor by going to the Edit menu and clicking Add To Chart. The following dialog box appears.

When you select an Object, the corresponding counters are displayed. Select a counter and click Add to begin monitoring the counter.


Using Performance Monitor on Solitaire

The following example is taken from the early days of the development of Windows NT. The Solitaire program was ported to Windows NT from 16-bit Windows. Initial users of the game complained about its performance when the cards cascade at the end of a winning game. Our first step was to run Performance Monitor. Because we didn't think Solitaire used the network, we logged the data across the network so we didn't interfere with any possible disk activity. We set the time interval to five seconds because the operation we wanted to time takes about 90 seconds. This gave us 18 data points.

To see the Solitaire cascade, it is not necessary to win the game. Start Solitaire and use the keystroke SHIFT+ALT+2 to start the cascade.

From the data, it's clear that there is a processor bottleneck. All the other chart lines are flat, except for the LAN activity generated by Performance Monitor. How can we be sure this activity is caused by Performance Monitor? The average NetBEUI Bytes Total/sec (3587) times the length of the run in seconds (340) is just about the size of the Performance Monitor log file (1120260 bytes).

The program was spending 41.445% of the time in privileged mode, and with a high context switch rate. Because the value of File Write Bytes/sec is close to the NetBEUI Bytes Total/sec, we can tell that the File Write Bytes/sec rate was caused by the redirector when it wrote Performance Monitor data. The interrupt rate is consistent with a system connected to a busy network, but not too active on it. We looked at which processes were using the processor.

With the activity from Solitaire and CSRSS, the processor developed the bottleneck. We decided to see if looking at the threads could give us any more information about what was causing this to happen. For clarity, we have omitted the 25 idle or near-idle CSRSS threads from the report shown here.

Now we can see the reasons for the context switches. Solitaire is calling CSRSS constantly, and most of the time is spent in CSRSS running a single thread. The processor is not spending a great deal of time running the Solitaire program. It would appear that Windows NT that has the problem.

By using the WAP profiling tool, no longer included with the Platform SDK but replaced by APIMon, we discovered that Solitaire was making a lot of calls to the GetPixel and SetPixel functions. To continue this Solitaire example, see Using CAP on Solitaire.


Call Attributed Profiler

The Call Attributed Profiler (CAP) allows you to profile function calls within an application. You use it to see how much time is spent in each function and in the functions called by that function. You can also use it to see how much time is spent in the function itself, ignoring the functions that it calls. This gives a complete picture of how time is spent when the application is running. This tool is available in the Platform SDK.

CAP uses an elapsed time clock to measure time in functions. This has both benefits and liabilities. The benefit is that you see where time is spent during disk or LAN activity. The disadvantage is that if your thread is preempted and a computation-intensive thread is run, it will appear as though the preempted function used the whole amount of time. Therefore, it is important to control the environment when using CAP.

CAP supports the following measurement methods:

  • Measuring calls from within an .exe file
  • Measuring calls from within a .dll file
  • Measuring calls from an .exe file to all of its DLLs
  • Measuring calls from a DLL to all of its DLLs
  • Measuring all calls to a specified DLL
  • Any combination of the preceding measurement methods

CAP creates a call tree of all the functions called in the module being profiled.

By default, CAP collects data only on functions compiled with a Microsoft C/C++ compiler or a compatible product from another vendor. You compile the source module with the -Gh compiler option, and a special call is inserted by the compiler at the start of every function. This invokes a measurement module called Cap.dll.

For more information, see the following topics:

  • Using CAP
  • Collecting CAP Data
  • Using CAP on Solitaire
  • CapView: A Visual Form of CAP


Using CAP

CAP consists of the following files.

File | Description
Cap.ini | Call Attributed Profiler initialization file.
Cap.dll | Call Attributed Profiler DLL.
Cap.lib | Call Attributed Profiler import library.
CapDump.exe | Allows collecting or clearing of profiling data and stopping profiling at any time.
CapSetup.exe | Allows attaching Cap.dll to Win32-based applications and detaching Cap.dll from Win32-based applications.
CapStats.exe | Allows parsing and summarizing of data in .cap files.

Windows NT/Windows 2000 does not ship with debugging symbols in its modules because it takes many megabytes of disk space to provide them. So, you should first run the APF32CVT utility on your application, with no action specified. This will give you a list of the system DLLs that need symbols. You can get the versions of the system with symbols (.dbg files) from your operating system compact disc. Then you rename the current system DLL; for example, type

ren gdi32.dll gdi32.nsm

Then copy the debug DLL from the CD to GDI32.dll. Once you have done this for all the DLLs you want to measure, you must shut down and restart the system so that the DLLs with symbols are loaded.

Next, set up an initialization file called Cap.ini in one of the following locations:

  • The current directory
  • The Windows directory
  • The root directory of the current drive
  • The root directory of drive C

The Cap.ini file has sections that control the set of .exe and .dll files profiled. Each .exe or .dll listed must be placed on a separate line. The format of this file must be correct; otherwise, the system might not start. The sections of Cap.ini are as follows.

Section | Description
[EXES] | A list of applications to be profiled. Each name must be on a new line. When Cap.dll initializes, it checks the current executable name against this list and will start profiling if the name is on the list. If the name is not on the list, CAP doesn't profile that process.
[PATCH IMPORTS] | A list of files to be profiled for imported entries. Each name must be on a new line. Listing a .dll or .exe file here causes the profiling of all functions called by the listed files.
[PATCH CALLERS] | A list of DLLs to be profiled for exported entries. Each name must be on a new line. DLLs listed here are profiled when called by the applications listed in the [EXE] section, or by any of their DLLs.
[NAME LENGTH] | The maximum length of a symbol to be printed in the output files. This number must be in the range from 20 to 2048. For C++ programs, this value should be set to at least 128 due to the name elaboration that is performed by the linker. If a symbol is longer than this value, it is truncated. If the field is not specified or is 0, the value defaults to 40. This section is optional.
[CHRONO FUNCS] | List of files and corresponding functions that start the chronological listing. For example, "test=SomeFunc" indicates that all functions called from the "SomeFunc" function of the "test" module are listed, until the call depth is less than or equal to the depth of "SomeFunc".
[EXCLUDE FUNCS] | List of files and corresponding functions that will be excluded from the profiling. However, if these functions call other functions that have not been excluded, they will be still included in the profiling.
[OUTPUT FILE] | Specifies a different drive and filename for the output file. For example, use filename=c:\results\solitaire\sol.cap.
[CAP FLAGS] | The following flags can be specified as "on" or "off": profile (profiling), dumpbinary (output in binary form), capthread (start 3 threads for CapDump), loadlibrary (init symbol table on LoadLibrary), setjump (intercept setjmp and longjmp), undecoratename (undecorated names), excelaware (delimiters for Excel import), regular dump (regular data), chronocollect (chronological listing collect), chronodump (chronological listing output), and slowsymbols (exhaustive symbol lookup)

Headers for the first three sections ([EXES], [PATCH IMPORTS], and [PATCH CALLERS]) are required in the Cap.ini file, but the contents of any section may be left blank.

Next, attach Cap.dll to the application process. Use one of the following methods to do this:

  • Recompile using the -Gh and -Zd options. Then link with Cap.lib and the -debugtype:coff and -debug:mapped,partial options. Run the application. If you are using Win32.mak, you can automatically specify these compiler and link options by using the following command line: nmake profile=1. For more information, see Building Applications Using Win32.mak.
    • -or-
  • Place Cap.dll in your system directory. Run CapSetup -A to attach Cap.dll to all Win32-based applications (it uses the AppInit_DLLs key in the registry). Administrator privilege is required. Reboot the system. Run your application. Only those applications listed in the [EXES] section of Cap.ini are profiled. You must explicitly list the modules whose functions you want profiled in the [PATCH IMPORTS] or [PATCH CALLERS] section of Cap.ini. Run CapSetup -D to detach Cap.dll when you have finished profiling. Reboot the system.


Collecting CAP Data

There are three ways to capture CAP profiling data:

  • Upon termination of the application, profiling data is written to a text file. The name of the text file is AppName.end.
  • Using the CapDump utility (CapDdump.exe). The name of the text file is AppName.cap. You can use the CapDump utility to stop profiling and clear or write profiling data for all applications being profiled, at any time. You can also use CapDump to change the extension of the output file. CapDump generates a log file, CapDump.log. It will contain any errors that occur during operation. For error-free operation, CapDump.log will be empty.
  • Using the CAP exported routines. These functions were declared using the standard-call calling convention; they take no parameters and have no return value. The function are:
    • StartCAP: Clear profiling data and start profiling.
    • StopCAP: Stop profiling.
    • DumpCAP: Write data for the current instance of Cap.dll. The name of the text file is AppName.cap.

Data files are created in the same directory as the application that is being profiled. Data is appended to data files with each write operation. A separate call tree is generated for each thread in the process. Different sections in the data file indicate data for different threads in the process. The following data is written:

  • Call depth in the tree
  • Function name
  • Number of calls
  • Total time for the function+callees
  • Time per call for the function+callees
  • Total time of the function only
  • Time per call of the function only
  • First time (function+callees)
  • Minimum time (function+callees)
  • Maximum time (function+callees)

You can use the CapStats utility for parsing and summarizing data stored in .cap files. CapStats can be used to perform the following tasks:

  • Extract data for one or more individual threads from a .cap file.
  • Write summary information into .CSV format that can be read into a data processing application, such as Microsoft Excel.
  • List callers and callees of any function that appears in the profile data.
  • Convert .cap files to .cab files, which CapStats can parse 10-100 times more quickly.

For example, to convert Sol.cap to Sol.cab, type:

capstats /B:sol.cab sol.cap

To summarize all functions in your file for import into a data processing application, type:

capstats /D sol.cab > sol.csv

The following samples can be used to get more detail about a particular function:

capstats /C:<funcname> sol.cab

or

capstats /T:<funcname> /B:<funcname>.cab sol.cab

For complete command-line syntax, type:

capstats /?


Using CAP on Solitaire

We want to measure the functions inside the Solitaire program, because we want to know where all those calls to GetPixel and SetPixel are coming from during the cascade operation. So we'll recompile Solitaire specifying the -Gh and -Zd compiler options, and we'll link specifying the CAP.LIB library and using the following linker options: -debugtype:coff -debug:full.

Note that you must make the following call in the initialization code for each thread before you recompile, or batching will confuse the data.

GdiSetBatchLimit(1)

Our Cap.ini file looks like this:

[EXES]
sol.exe

[PATCH IMPORTS]
sol.exe

[PATCH CALLERS]

This will profile Sol.exe and measure any calls it makes to functions in other modules, including the system DLLs. In our case, there is nothing after the [PATCH CALLERS] header. You should use that section to profile particular DLLs that you've developed after you have listed in the [EXES] section the applications that call your DLLs.

First we start CapDump, and then we start the recompiled version of Solitaire. We'll tell CapDump to clear the counters because we are not concerned at present about the performance while Solitaire starts. After CapDump clears the counters, we press SHIFT+ALT+2 to activate the cascade. After the cascade is completed, we shift to CapDump to dump the data. Data files with the default .cap extension appear in the directory where each measured application resides.

A center section of the results from the Sol.cap file produced by this run are shown following. This first output shows function times including called functions:

T h r e a d  #1:   (pid|tid=0x6f|0x40   Client:pid|tid=0x0|0x0)
                                         ----- Rtn + Callees -----
Depth Routine                            Calls   Tot Time   Time/Call
  7   SOL.EXE: _DrawCardPt                4267   89561181   20989
  8   SOL.EXE: _cdtDrawExt                4267   89359010   20941
  9   SOL.EXE: _HbmFromCd                 4267     166394      38
 10   USER32.DLL: _LoadBitmapA               4      43754   10937
 10   GDI32.DLL: _CreateCompatibleDC         8       3940     492
 10   GDI32.DLL: _CreateCompatibleBitmap     4       4959    1239
 10   GDI32.DLL: _SelectObject              16       6485     404
 10   GDI32.DLL: _BitBlt                     4      31462    7865
 10   GDI32.DLL: _DeleteObject               4       1563     390
 10   GDI32.DLL: _DeleteDC                   8       3728     466
  9   GDI32.DLL: _CreateCompatibleDC      4267    2849629     667
  9   GDI32.DLL: _SelectObject            8534    3495921     409
  9   SOL.EXE: _SaveCorners               4267   29082632    6815
 10   GDI32.DLL: _GetPixel               51204   25928990     506
  9   GDI32.DLL: _BitBlt                  4267   19896612    4662
  9   SOL.EXE: _RestoreCorners            4267   23112842    5416
 10   GDI32.DLL: _SetPixel               51204   20224631     394
  9   GDI32.DLL: _DeleteDC                4267    2892566     677
  9   GDI32.DLL: _PatBlt                  5776    2863906     495
  9   GDI32.DLL: _SetPixel                5776    2273112     393
  7   SOL.EXE: _FAbort                    4267    2632621     616

This second output shows function calls excluding called functions.

T h r e a d  #1:   (pid|tid=0x6f|0x40   Client:pid|tid=0x0|0x0)
                                         ----- Rtn - Callees -----
Depth Routine                             Tot Time   Time/Call
  7   SOL.EXE: _DrawCardPt                  202170          46
  8   SOL.EXE: _cdtDrawExt                 2725391         637
  9   SOL.EXE: _HbmFromCd                    70500          15
 10   USER32.DLL: _LoadBitmapA               43754       10937
 10   GDI32.DLL: _CreateCompatibleDC          3940         492
 10   GDI32.DLL: _CreateCompatibleBitmap      4959        1239
 10   GDI32.DLL: _SelectObject                6485         404
 10   GDI32.DLL: _BitBlt                     31462        7865
 10   GDI32.DLL: _DeleteObject                1563         390
 10   GDI32.DLL: _DeleteDC                    3728         466
  9   GDI32.DLL: _CreateCompatibleDC       2849629         667
  9   GDI32.DLL: _SelectObject             3495921         409
  9   SOL.EXE: _SaveCorners                3153642         738
 10   GDI32.DLL: _GetPixel                25928990         506
  9   GDI32.DLL: _BitBlt                  19896612        4662
  9   SOL.EXE: _RestoreCorners             2888211         676
 10   GDI32.DLL: _SetPixel                20224631         394
  9   GDI32.DLL: _DeleteDC                 2892566         677
  9   GDI32.DLL: _PatBlt                   2863906         495
  9   GDI32.DLL: _SetPixel                 2273112         393
  7   SOL.EXE: _FAbort                      347749          81

The leftmost column is the function call nesting depth. This starts at zero with the first function call that CAP encounters. If a function is called but has not returned when the data is dumped, there will be an asterisk to the left of this number. The next column shows the module name followed by the function name. If the function name is not known because the COFF symbols with the function names in them are not contained in the module, ???: ??? is shown instead of the module and function names.

This section of the results, where Sol.exe executed for 89 seconds, starts at call level 7 with DrawCardPt, which was called 4267 times. It called cdtDrawExt each time it was called, and that called HbmFromCd. The program didn't spend much time here: only 1.6 out of the 89 seconds. HbmFromCd called the LoadBitMapA function four times. This is a Win32 API function located in User32.dll. The final "A" in this function name means this is the ASCII form of the call, indicating that Solitaire is not a Unicode application (or else the function would have a final "W"). The HbmFromCd call uses some graphics primitives in GDI32.dll, but only a few times, even though it was called 4267 times. So it is not the central cause of the poor performance.

The call level returns to 9, which means cdtDrawExt at level 8 is back in control. We see that even though we spent 89 seconds in this routine and the routines it called, we spent only 2.7 seconds in the routine itself. The other 86-plus seconds were in the functions it called.

The cdtDrawExt function calls CreateCompatibleDC each time it is called, and then SelectObject twice on every call. We have more than 6 seconds between them. Then there is a call to SaveCorners, which takes 29 seconds. We see only 3.1 seconds in SaveCorners itself, so the rest must be in GetPixel. A similar story applies to RestoreCorners and _SetPixel right after the call to BitBlt.

We went to the developer porting Solitaire at this stage in our testing and asked what SaveCorners and RestoreCorners were doing. We discovered that they modified three pixels on each corner of the bitmap of a card to make the corner look a little more rounded. However, because each call forced a client-server transition, we decided to remove the calls altogether during a cascade. This was a very small change, just a few lines of code, but it made the Solitaire cascade twice as fast.


CapView: A Visual Form of CAP

Looking at the CAP output files can be tedious if you have a large program with hundreds or thousands of functions. The CapView utility provides a great visual alternative. This utility is available in the Platform SDK.

The following figures show some of the data from running the repaired Solitaire as it is displayed by CapView:

Each box in the CapView tree represents a line in the Sol.cap file. If you zoom out you see the overview, and if you zoom in you can see the details of each line.

The first figure in the box is the number of calls made to that routine.

The rightmost number in the next line of figures is the time spent in the function itself, expressed in microseconds. The left number is the attributed time. This is the time spent in the function, expressed as a percentage of the time in the function plus the time in the functions it calls. The middle figure is time in the function as a percentage of time in the entire program.

In the last line, the rightmost number is the attributed time. The middle number is the attributed time in this function as a percentage of time in the program. And the leftmost number is the time in this function as a percentage of attributed time in the calling function.

The list view of CapView is illustrated following. The attributed columns are shown, but the function-only columns are also available.


APIMon

The Application Monitor (APIMon.exe) counts and times all Win32 function calls. It can optionally monitor page faults caused by the monitored application and report them by Win32 function call. This tool is included in the Platform SDK.

APIMon is a performance monitor that can help you tune your application. The data can be used to determine the Win32 functions that have the largest times and counts. APIMon generates two types of reports: a report containing all calls, showing their counts and times, and a report showing a trace of all calls as they occurred.

For more information, see APIMon.hlp, which is included in the Platform SDK.


Profile

The Sampling Profiler (Profile.exe) is an easy-to-use tool that records the number of times each function of an application is called during the course of its execution. This tool is included in the Platform SDK.

While the application runs, Profile samples its instruction pointer periodically, and records the value of the instruction pointer each time it takes a sample. When the application terminates, Profile looks up the recorded address values in the symbol files to determine the function names. Then Profile tabulates the results and writes them to the specified file.

The output file consists of three comma-separated fields. The first field contains the number of times a sample occurred in the function. The second field contains the name of the module containing that function and the third field contains the name of the function within the module, followed by its virtual address. In a verbose listing, each of these function entries is followed by a listing of the actual addresses that were sampled.


Profile Installation

The following files must be located on the system path before you can use Profile.

File | Description
Profile.ex | Sampling Profiler
PSAPI.dll | Process Support API Library

Profile must have access to the application's symbols to produce the most meaningful output. The symbols must be located in the path described by the _NT_SYMBOL_PATH environment variable. Be sure to set this variable to the correct path before using PROFILE.


Using Profile

The syntax for calling Profile is as follows:

profile [options]
/a
Display all functions or addresses that were sampled.
/b nnn
Set the sample address granularity. Set profile bucket size to 2**nnn bytes. The default setting is 4 bytes.
/f filename
Send the output to the file named filename. The default setting is Profile.out.
/i nnn
Set sample interval to nnn (in 100-nanosecond units). The default value is 488.2 microseconds (/i4882).
/k
Allow profiling of the kernel-mode functions called by the application being profiled.
/s profilesource
Use profilesource as the profile interrupt source instead of clock interrupt. This option is not supported on all platforms. The supported platforms and options are listed following.
Platform | Options
ALPHA align
branchinstructions
branchmispredicts
dcachemisses
icachemisses
loadinstructions
pipelinedry
pipelinefrozen
totalnonissues
storeinstructions
totalissues
MIPS | align

/S profilesource
Use profilesource as the secondary profile interrupt source. The options are the same as those specified for the /s option.


Sample Profile Command Lines

The following command line is used to profile the application MyProg.exe using the default settings. Profile writes the output to the default file, Profile.out.

profile myprog.exe

The following command line profiles the program MyProg.exe, monitoring both user mode and kernel mode functions executed by this process. The output is written to the file MyProg.dat.

profile /k /fmyprog.dat myprog.exe


Tuning the Working Set of Your Application

The working set of a program is a collection of those pages in its virtual address space that have been recently referenced. It includes both shared and private data. The shared data includes pages that contain all instructions your application executes, including those in your DLLs and the system DLLs. As the working set size increases, memory demand increases.

The Working Set Tuner (WST) can help you reduce the amount of space your program takes in RAM. You should tune your application's working set even if you are satisfied with its performance. Your program will coexist with other running applications, so it's a good idea to save space. The Windows NT/Windows 2000 code itself has been tuned with WST.

Even if you are not concerned about the RAM your applications takes away from other applications, you probably care about the time it takes to load your own program into RAM from disk. WST can help with that too.

WST can improve the speed of your program in another way. It can reduce the space your application requires in the processor cache and the translation buffer (another processor cache used for page translation). Not only will your application code execute faster, it will interfere less with the code in Windows NT/Windows 2000.

  • About the Working Set Tuner
  • Using the Working Set Tuner
  • Looking Inside Your Working Set


About the Working Set Tuner

WST reduces the number of code pages that have to be in RAM for your program to execute. It reduces them by helping the linker put your executable together in a way that minimizes the number of pages you use at a time. With any application, there are probably many optimal assignments of functions to pages. WST will produce results at least as good as a programmer could achieve by hand in a more reasonable amount of time.

Typically, your executable image is put together in the order in which address references are resolved. This method has nothing to do with the need for particular routines to reside together in memory, because lots of functions get called only under error conditions or other unusual situations. However, the references to these routines are near references to routines that are used all the time.

WST provides a packing list to the linker so the linker can place functions into the executable image in the order that most reduces paging. The linker place the most frequently used functions together in the .EXE image. This continues in order of usage until the linker reaches the functions that are never referenced. It places these at the end of the .EXE in "don't care" order.

Consider the following example.

status = DoSomethingFirst( );
while (status == WONDERFUL)
{
    status = ProcessNormally( );
} else
{
    PressThePanicButton( );
}

If this is the first time the linker has seen these symbols, it would put DoSomethingFirst in the .EXE, followed by ProcessNormally, and then it would put in PressThePanicButton. But DoSomethingFirst is only used during initialization, and PressThePanicButton is only called under extreme circumstances. If the linker placed ProcessNormally in the .EXE with other routines that are used frequently, DoSomethingFirst with routines that are used only to initialize the application, and PressThePanicButton somewhere else, it would reduce paging. When the image is ordered that way, pages loaded when ProcessNormally is first executed would likely contain only routines that are used frequently, the page containing DoSomethingFirst would likely be discarded after initialization, and the page containing PressThePanicButton would be loaded only on error.

Typically, WST provides between 25% and 50% savings on code space used. You can expect a 30% reduction in your code space for the test scenario that you measure. But the operational results of your efforts depend almost entirely on how well you designed your test scenario. Using WST without proper preparation does not help much.

See How the Working Set Tuner Works.


How the Working Set Tuner Works

WST determines which functions are used together by starting with a measurement of your application. For WST to be effective, you must define a test scenario that will execute all the commonly used functions in your application. Your test scenario should spend the most time executing the most commonly used function.

Like CAP, WST is called every time a function in your application is called. Each function in your application is represented by a bit. This bit is set when the function is called. Periodically, WST takes a snapshot of all the bits, and then clears them. The default time interval is 1000 milliseconds, but you can adjust this. You may want to increase the interval if the scenario is very long, to reduce the time spent in the analysis phase. This should not effect the overall results very much.

The snapshot of the bits tells WST which functions were called during the last time interval. In sequence, the snapshots give a history of function references over time. Because the bits are cleared after every snapshot, a function with all its bits set is referenced on every snapshot. If a function had no bits set, it was never called during the test scenario.

The following table shows how this looks. We ran WST on the Solitaire cascade of cards. If we were really trying to optimize Solitaire, this is not the scenario we would use; playing a game would have been a much better choice. But playing a game of Solitaire is difficult to automate with testing tools, so we chose this simple case instead.

Before tuning After tuning
00000000000000000000000000000000

11111111111111111111111111100000

00000000000000000000000000000000

11111111111111111111111111100000

00100000000000000000000000000000

11111111111111111111111111100000

11111110111011110000100000000000

00001111111111111111111111100000

00101000000000000000000000000000

00001111111111111111111111100000

00001000000000000000000000000000

00001111111111111111111111100000

00000000000000000000000000000000

00001111111111111111111111100000

11111111111111111111111111100000

00001111111111111111111111100000

00000000000000000000000000000000

00001111111111111111111111100000

00000000000000000000000000000000

11111110111011110000100000000000

00000000000000000000000000000000

00101000000000000000000000000000

00000000000000000000000000000000

00101000000000000000000000000000

00000000000000000000000000000000

00100000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00001111111111111111111111100000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00100000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00100000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00000000000000000000000000000000

00001000000000000000000000000000

00001000000000000000000000000000

00001000000000000000000000000000

00001000000000000000000000000000

00001000000000000000000000000000

Each line corresponds to a function. Each function has a row (left-to-right) and each column of 1s and 0s represents a snapshot of each function's activity at that moment.

In the first column, the functions are ordered as they appear in the executable after a normal compile and link of the application. Not all the functions in the program are shown, just the ones at the start of the executable image. Each 0 or 1 corresponds to a Time Interval. The bit is 0 if the function was not referenced during that particular time interval during the cascade, and 1 if it was referenced.

The second column shows the routines that are at the start of the packing list after tuning the working set. These are all the routines that have their bits set during the test. The remaining routines in the image were not used during the cascade. Notice the string of routines near the bottom which had only one bit set. These occurred because we moved the mouse across the cascade while it was running. If we had not done this, these routines would have remained scattered throughout the image. If you automate your test scenario (which you should do unless you plan to do the test by hand every time your application changes), this is one time when some use of the mouse is a good idea. For most applications, you can test any screen resolution in your scenario. However, if the screen resolution affects the operation of your application, you should take the time to make your test independent of screen resolution.


Using the Working Set Tuner

WST consists of the following files:

File | Description
WST.INI | Working set tuner initialization file
WST.DLL | Working set tuner DLL
WST.LIB | Working set tuner import library
WSTDUMP.EXE | Allows collecting or clearing of WST data and stopping data collection at any time
WSTUNE.EXE | Utility for creating the packing list from collected data
WSTCAT.EXE | Concatenates multiple data files

Using the WST is similar to using CAP, from which it is derived.

The following steps are involved in using WST:

  • Preparing your application
  • Collecting WST data
  • Analyzing WST data
  • Linking with the packing list


Preparing Your Application

First, create a WST directory in the root of your C drive. Create the WST.INI file in the C:\WST directory. This file contains the following required section headers:

Section | Description
[EXES] | A list of applications to be tuned. Each name must be on a new line.
[PATCH IMPORTS] | A list of .DLLs and .EXEs to be tuned for imported entries. Each name must be on a new line.
[TIME INTERVAL] | The elapsed time between recording snapshots, in milliseconds. If left blank, 1000 is used.

Headers for these section are required to be in the WST.INI file, but you can leave the contents of any section blank.

For example, to tune Solitaire, our WST.INI looks like this:

[EXES]
sol.exe
[PATCH IMPORTS]
[TIME INTERVAL]

Next, attach WST.DLL to the application process. If you are using Microsoft development tools, this is done using the following steps:

  1. Recompile using the -Gh, -Ox, and -Zd options.
  2. Link with WST.LIB and the -debugtype:coff and -debug:mapped,partial options. You can also use the -WS:aggressive option to indicate that the memory manager can aggressively trim the working set of the process.
  3. Place WST.DLL in a directory on your path.

Run your application. Only those applications listed in the [EXES] section of WST.INI are tuned.

Note If you are using WIN32.MAK, include the $(CDEBUG) macro in your compile options, the $(LDEBUG) macro in your linker options, and TUNE=1 on your NMAKE command line. This will complete steps 1 and 2 above. For more information, see Building Applications Using WIN32.MAK.


Collecting WST Data

There are two ways to capture WST data:

  • Upon termination of the application, WST data is written to text files.
  • Using the WSTDUMP utility (WSTDUMP.EXE). You can use this utility to specify which portion of your application's operation is tuned. You can also clear and write WST data at any time.

The data is written into the C:\WST directory, in files with names of the form APPNAME.WSP and APPNAME.TMI. If you write data multiple times, the file extensions from each run will be modified to .W?? and .T??, where ?? is a hexadecimal number between 0x01 and 0xFF. The number indicates the run number.

You can concatenate multiple .WSP and .TMI files for analysis using the WSTCAT utility. It produces composite .WSP and .TMI files, after renaming the original ones to .WXX and .TXX. The weight of the files in the concatenated result depends on the length of each experiment, or more accurately—because you might have varied the time interval—on the number of snapshots in each. The bits for each function from the multiple files are concatenated.


Analyzing WST Data

When you have finished the measurement, use the WSTUNE utility to create the packing list. The syntax is as follows:

wstune [[options]] modulename.wsp
WSTUNE has the following options:
/O
Write data to the file. The extension is .DT if tuned, .DN if not tuned.
/D
Write analysis data only; do not write the strings of bits.
/N
Analyze the strings of bits, do not write any data.
/?
Display usage information.

For example:

wstune /o modulename.wsp

The data files created by WSTUNE are:

File | Description
.DT | Data tuned. Contains the analysis data/strings of bits for all functions called in the packing list order.
.DN | Data not tuned. Contains the function called in unpacked order.
.PRF | Contains the packing list to be used in tuning.
.WSR | A worker index file created for internal use only.


Linking with the Packing List

To implement the working set improvements:

  • Recompile your application using the -Gy option. This option assures that the linker knows the location of the start and end of each function. Be sure to remove the -Gh option used to prepare the application for tuning.
  • Relink your application using the -order:@modulename.prf option, where modulename.prf is the name of the packing list that was generated by WSTUNE.


Looking Inside Your Working Set

You may want to get a better understanding of the pieces inside the working set of your application. For example, you may save a lot of code space with the Working Set Tuner only to discover that the code space is only a small portion of your overall working set. In fact, this might even be something you want to do before you go to all the trouble to tune your code.

You probably want to make these measurements on a test computer. Choose a computer large enough to hold your entire working-set tuning test scenario in memory. You may need to discover this size through the trial and error process described in this section.

To do this, you can use a tool called Virtual Address Dump, or VADump. The VADump tool looks inside the working set of a process and determines the nature of each page.

First, link your application using the -debug and -debugtype:coff options, so you get full use from VADump.

Start your application, then start PView. Use PView to note the process identifier of your application. You'll need to supply this to VADump. You should convert the process identifier from hexadecimal to decimal, since VADump expects it in decimal format. Or you can use the TLIST utility to get the process identifier directly in decimal form.

Set up your test scenario. Start Performance Monitor and leave it running, and command window so you can run VADump. Type the following in the command window, but don't press ENTER yet.

vadump -o -m -p PID > app.vad

The -o option tells VADump to monitor the working set in the original style, the -m option tells VADump to use the mapped symbols, and the -p option indicates the process identifier (PID), in decimal, of the process to measure. In the example command line, the output is directed to the file APP.VAD. Again, do not press ENTER yet.

You should flush everything from memory and the disk cache. You can use the CLEARMEM utility from the Resource Kit. Running CLEARMEM a few times generally completes the flush; however, you may want to watch your working set with Performance Monitor to be sure. Then switch to your application and execute the test scenario you devised for tuning the working set.

Now switch to the VADump window and press the ENTER key execute the VADump command created earlier. The results will be put in APP.VAD if you use the command line we showed earlier.

Take a look at Performance Monitor again and get the new size for your application's working set. This is likely to be a bit larger now than before, because VADump itself must bring some pages into the working set to scan all the page tables and working set entries for your application.

Run the scenario in your application again. Performance Monitor should get no page faults in your application during this run. If it does, you may not have enough memory on the system to hold your application's working set.

The output from VADump shows the nature of each page in the working set of your process:

0x00010000 PRIVATE Base 0x00010000
0x00020000 PRIVATE Base 0x00020000
0x0012d000 PRIVATE Base 0x00030000
0x0012e000 PRIVATE Base 0x00030000
0x0012f000 PRIVATE Base 0x00030000
0x00130000 PRIVATE Base 0x00130000
0x00140000 PRIVATE Base 0x00140000
0x00141000 Process Heap
0x00142000 Process Heap
0x00143000 Process Heap
0x00240000 PAGEFILE_MAPPED Base 0x00240000
0x00250000 DATAFILE_MAPPED Base 0x00250000 unicode.nls
0x00251000 DATAFILE_MAPPED Base 0x00250000 unicode.nls
0x00253000 DATAFILE_MAPPED Base 0x00250000 unicode.nls
0x00260000 DATAFILE_MAPPED Base 0x00260000 locale.nls
0x00263000 DATAFILE_MAPPED Base 0x00260000 locale.nls
0x00270000 DATAFILE_MAPPED Base 0x00270000 sortkey.nls
0x002c0000 DATAFILE_MAPPED Base 0x002c0000 sorttbls.nls
0x002d0000 PRIVATE Base 0x002d0000
0x002e0000 PAGEFILE_MAPPED Base 0x002e0000
0x002f0000 PRIVATE Base 0x002f0000
0x01000000 menappl.exe
        (1000) _except_list
0x01001000 menappl.exe
        ( 165) LogDisplayDlgProc@16
        (  24) GetSystemPerfData@16
        ( 1a0) UpdateSystemData@8
        (  1c) MemorySize@4
        (  29) GetObjectDefByTitleIndex@8
        (  14) LogCollecting@4
        ( 113) DrawAlerts@8
        (  d2) DrawLog@8
        (  4c) SmallFileSizeString@8

The page virtual addresses appear on the left. For each section of address space, the base is shown on the right. PRIVATE pages are dynamic data pages that are private to the process. Process Heap pages are dynamically allocated from the process heap. It can be difficult to determine who is using this space, and you may need to look at pointers within your application using the debugger.

The system pages are those allocated for the page tables and for the working set packing list itself. This might be larger than your application actually needs, because VADump needs to scan them. So use Performance Monitor as described to determine the difference. For this example, when we looked at the working set of Performance Monitor while charting, running VADump added 5 pages to the working set.

If COFF symbols are included and the module was linked with the -debug flag, other pages that belong to specific modules are indicated by listing which public symbols occur within the page. This helps you to understand why a particular page has been brought into memory. If the module was compiled without the correct flags, you will see only the module name.

Any pages listed as belonging to the module "Error" are pages that did not resolve to a particular module.

You will also find some DATA pages at the upper end of the application's address space. These are for such system-related items as the Process Environment Block, the Thread Environment Blocks, the Per-Thread Data Area, and so on.

Pages in the range starting at 0xC0000000 are page table pages. They are listed showing the range of pages they map, how many of those are in memory (these are called resident pages), and the range of resident pages and their modules.

Finally, there is a summary of pages and who owns them. These pages summarize the pages already listed, so avoid counting them again.

See Requested Working Set Size.


Requested Working Set Size

After you have optimized your working set and know approximately what it is, you may have to alter your application's requested working set size for efficiency. Keep in mind that setting an unreasonable working set size can degrade performance system-wide.

To find out the requested minimum and maximum sizes of the working set for your application, call the GetProcessWorkingSetSize function. The virtual memory manager attempts to keep enough memory for the minimum working set resident when the process is active, but keeps no more than the maximum size.

You can also set these values using the SetProcessWorkingSetSize function. Setting these values is not a guarantee that the memory will be reserved or resident.

Calling VirtualUnlock on a range of memory that is not locked releases pages from the working set.


Performance Utilities

The Platform SDK contains several useful performance utilities. They are discussed in the following topics:

  • Bind
  • ExCtrLst
  • MemSnap
  • PerfMtr
  • PStat
  • PWalk
  • Rebase
  • VADUMP
  • WPerf


Bind

The linker stores addresses of exported DLL functions in a table that is separate from the table that contains the names of the exported DLL functions. Calls to exported DLL functions are made using an indirect jump through the table that contains the addresses. You can minimize load time by using Bind to bypass this lookup. Bind your executable with all of your DLLs, plus the system DLLs, by running Bind once you have installed the application on the computer where you will be running it or by using the functions described in Debug Help Library .

The syntax for Bind is as follows:

bind [options] image-names

Bind has the following command-line options:

-o
Disable new import descriptors.
-p
DLL search path.
-s symbol_dir
Update associated .DBG files. If the symbol_dir directory is specified, Bind searches for the .DBG files in the directories SYMBOL_DIR\EXE and SYMBOL_DIR\DLL.
-u
Update the image.
-v
Verbose output.
-y
Allow binding on images located above 2 GB in memory.
-?
Display command-line syntax.


ExCtrLst

Windows NT/Windows 2000

The extensible counter list utility (EXCTRLST.EXE) is used to obtain information about the extensible performance counter dynamic-link libraries (DLLs) on a computer running Windows NT/Windows 2000. This utility lists the applications, drivers, and services that are registered to provide performance data through the performance registry. You can use this utility for finding information and for troubleshooting.

  • Extensible Performance Counters
  • Using Extensible Performance Counters
  • Using EXCTRLST


Extensible Performance Counters

Windows NT/Windows 2000

Windows NT/Windows 2000 allows you to measure many aspects of its performance and status. This performance data is collected in the registry and can be displayed using the Performance Monitor (PERFMON.EXE).

The extensible performance counter interface allows applications, drivers, and services to add performance data to the registry, using an extensible performance counter DLL. This performance data can be displayed in Performance Monitor, along with the system performance data. The EXCTRLST utility uses the registry to find the applications, drivers, and services that have registered an extensible performance counter DLL.

For more information, see Performance Monitoring.


Using Extensible Performance Counters

Windows NT/Windows 2000

It is possible for a single extensible performance counter DLL to provide performance information for one or more applications, drivers, or services. Each software component that provides performance counters must store the following configuration information in the registry.

Configuration item | Description
DLL name | The name of the DLL that contains the functions used by the performance registry.
Open procedure | This function is called once when the software component's performance interface is first started. It is used to initialize the DLL.
Collect procedure | This function is called repeatedly to collect the current performance data for the software component.
Close procedure | This function is called when the handle to the performance registry is closed.
Counter and help identifiers | These strings identify the counter and object names that are stored in the registry and referenced by a numeric index. The index values for extensible counters are defined when the DLL is installed. This is usually during application or service installation. Some extensible counter DLLs use pre-assigned index values. The index values for those counters are not displayed; instead, N/A appears.


Using EXCTRLST

Windows NT/Windows 2000

When the EXCTRLST utility is started, it scans the registry to determine which applications, devices, and services have registered extensible performance counter DLLs. These DLLs are listed in the list box of the display along with the corresponding application, driver, or service. The EXCTRLST utility does not test for the existence of the DLLs.

The following table contains descriptions for the different fields displayed in the EXCTRLST dialog box.

Field | Description
Machine name | The name of the machine from which the information is read. The default value is the local machine. However, you can use the name of any machine for which you have permission to read the registry.
Refresh | When you click this button, the utility updates the display with current information from the registry of the selected machine.
Sort Order | The sort order for the items displayed in the Extensible Performance Counters list box. The default sort order is By Library Name, which sorts the list in alphabetical order by the name of the DLL. If By Service Name is selected, the list is sorted by the name of the service entry in the registry.
Extensible Performance Counters | A list box that contains the names of the services that provide performance counters, and the DLL that provides this information. The order is determined by the Sort Order selection.
DLL Name | The entry found in the registry for the DLL that the operating system is to load for the performance data provided by this service. Either the file must be located in the system path, or you must provide the fully qualified path to the DLL. If the DLL is not found, the system logs an error in the Application event log.
Open Procedure | The name of the DLL function that initializes the performance functions for the service. This function must be exported by the DLL and must return success. If this function is not found in the DLL or if it returns an error, the system logs an error in the Application event log.
Collect Procedure | The name of the DLL function that collects the performance data for the service. This function is called each time an application, such as Performance Monitor, requests performance data. If this function is not found in the DLL or causes an error, the system logs an error in the Application event log.
Close Procedure | The name of the DLL function that performs any termination or cleanup when the application requesting performance data closes its interface to the performance registry. If this function is not found in the DLL, the system logs an error in the Application event log.
Counter ID Range | When the extensible performance counter DLL is installed, the system assigns a range of Index values to its object and counter name strings. The values assigned during installation are displayed here. If the service uses pre-assigned index values, this entry is not applicable, and the value of this field is N/A. If there is a problem with the entry for the service, its counters are not displayed, and this field is Not Found.
Help ID Range | When the extensible performance counter DLL is installed, the system assigns a range of index values to its object and counter descriptions. The indices used are the corresponding counter or object name string index + 1. The values assigned during installation are displayed here. If the service uses pre-assigned index values, this entry is not applicable, and the value of this field is N/A. If there is a problem with the entry for the service, its counters are not displayed, and this field is Not Found.

Note The values for the Counter ID Range and Help ID Range fields must correspond to the entries found in the following registry key:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Perflib\<LangID>\Counter

where <LangID> corresponds to the specific entry for the default language on the machine (for example, 009 indicates that the language is English). If these values do not correspond, the counters and objects described for the service are not displayed correctly.


MemSnap

The Memory Snapshot utility (MEMSNAP.EXE) logs system memory usage to a log file. The following is the command-line syntax for MEMSNAP:

memsnap [LogFile]
LogFile
The name of the log file. The default is MEMSNAP.LOG.

The log file contains the following information for each active process:

  • Process ID
  • Process Name
  • Working Set
  • Paged Pool
  • Non-Paged Pool
  • Pagefile
  • Commit
  • Handles
  • Threads


PerfMtr

Windows NT/Windows 2000

PerfMtr can display a variety of system performance information. The command-line syntax is:

perfmtr

PerfMtr begins by displaying CPU usage. Use the following keystrokes to change the type of performance information displayed:

Key | Displays
C | CPU usage
V | VM usage
F | File Cache usage
R | Cache Manager read and write operations
P | Pool usage
I | I/O usage
X | x86 VDM stats
S | Server stats

The information is periodically updated, and will scroll off the screen. Type H to repeat the header for the current information type. You can also type Q to quit.


PStat

PStat lists statistics for each process. The following is the command-line syntax for PStat:

pstat [-u] [-s] [-v]
-u
Display statistics for user-mode processes.
-s
Display statistics for time the system spends in kernel mode.
-v
Specifies verbose mode.


PWalk

Process Walker (PWALK.EXE) provides a complete listing of the memory usage of a particular process. It displays the process' entire user-mode address space, as well as which DLLs are loaded and where the code, data, and stack are located. This tool is extremely useful for tracking down memory leaks and examining memory usage.

Each line in the list produced by PWALK contains the following:

  • Address
  • State (committed, reserved, or free)
  • Protection (read-only, read-write, or none)
  • Size
  • Base Address
  • Object
  • Section
  • Name

You can sort the list by address, state, protection, size, or base address.

Double-click on any line that displays committed memory to view the contents of the memory. Click Process statistics from the View menu to obtain additional process statistics such as the total committed, reserved, and free memory. Click System statistics from the View menu to obtain system statistics such as physical memory, pagefile, and disk space.


Rebase

Rebase is a command-line tool that you can use to specify the base addresses for the DLLs that your application uses.

The base address of a DLL is the location in virtual memory where the loader attempts to place the DLL. It is generally specified at link time. If a DLL cannot load at its base address because the memory is already occupied, the loader places the DLL elsewhere in virtual memory, then updates all calls into the DLL to reflect the new base address. Making these changes can be time consuming, because the image must be copied to the pagefile and modified for the new address. If you have a large application that uses many DLLs, it is important for each DLL to have a different base address to minimize load time. You will receive the following warning from the loader if a DLL is relocated:

LDR: Automatic DLL Relocation in ProcessName.
LDR: DLL ImageName base ImageBase relocated due to collision with ExistingImage.

When you pass all the DLLs for your application to Rebase, it bases each DLL at a unique address. You should not pass your .EXE file to Rebase. It is the first thing to be loaded, so there is no chance that something else can already be loaded at its default load address.

The system DLLs are currently based in memory from 0x70000000 to 0x78000000 (0x68000000 to 0x78000000 on MIPS). Therefore, you should base your DLLs from 0x60000000 to 0x68000000. One possible scheme is to choose a base address based on the first letter of the DLL name.

First letter | Base address
A - C | 0x60000000
D - F | 0x61000000
G - I | 0x62000000
J - L | 0x63000000
M - O | 0x64000000
P - R | 0x65000000
S - U | 0x66000000
V - X | 0x67000000
Y - Z | 0x68000000

It is best to base DLLs from the top of the address range down, instead of from the bottom up. Dynamic memory is allocated from the bottom up and if a DLL tries to load where dynamic memory has been allocated, it will be relocated, just as if a DLL was loaded at that address.

To use Rebase to base your DLLs, use the following syntax:

rebase [options] image-names

Rebase has the following command-line options:

-b initial_base
Specify initial base address. It is mandatory that you use either the -b or -i option.
-i coffbase_filename
Read base addresses from the file coffbase_filename. It is mandatory that you use either the -b or -i option.
-c coffbase_filename
Write the list of base addresses to the file coffbase_filename. The filename extension is not included. Use -C to include filename extensions.
-d
Perform a top-down rebase.
-l logFilePath
Write image bases to log file.
-z
Allow rebasing the system file.
-R image_root
Set a root directory for use by the -G, -O, -N options.
-G filename
Group specified images together in address space. May be used multiple times. Specify a root directory with the -R option.
-N filename
Leave specified images at their original addresses. May be used multiple times. Specify a root directory with the -R option.
-O filename
Overlay images in address space. May be used multiple times. Specify a root directory with the -R option.
-x symbol_dir
Extract debug information into separate .DBG file before rebasing. Use symbol_dir to place the .DBG files are placed in the directories symbol_dir\EXE or symbol_dir\DLL, depending on whether the source is an .EXE file or a .DLL file. To specify the current directory for the symbol directory, use a period (.).
-p
Used with the -x option. Remove private debug information when creating .DBG files.
-a
Used with the -x option. Extract all debug information into the .DBG files.
-f
Strip relocations after rebasing the image. Causes failure to load.
-s
Just sum image range.
-q
Minimal output.
-v
Verbose output.
-?
Display command-line syntax.

Alternatively, you can use the ReBaseImage function.

Note If you shared a section in your DLL, the loader will fail to load the image if it needs to be relocated and the shared section contains any relocations. This is a good reason to use named shared memory instead of using shared sections.


VADUMP

Virtual Address Dump (VADUMP) creates a listing that contains information about the memory usage of a specified process.

The following is the command-line syntax for VADUMP:

vadump -p pid
-p pid
The process identifier of the process whose address space is to be listed, in decimal.

The listed produced by VADUMP includes the following:

  • Each address, along with its size, state, protection, and type.
  • Total committed memory for the image.
  • Total committed memory for the .EXE file.
  • Total committed memory for each .DLL file, including system .DLL files.
  • Total mapped committed memory.
  • Total private committed memory.
  • Total reserved memory.
  • Information about the working set.
  • Information about paged and nonpaged pool usage.


WPerf

WPerf is another performance monitor that presents data a little differently than Performance Monitor.

Click a corner of the window when it appears, and enlarge the window.

Double-click on the window to display the Select menu. The dialog box that appears allows you to select the counters whose information is to be displayed. Two of these counters are not available through Performance Monitor, because they are supported only by certain RISC machines: 1st Level TB Fills/Sec and 2nd Level TB Fills/Sec. The TB is the page translation buffer in the processor, which is used to translate virtual addresses to physical addresses. On some RISC machines, resolving TB misses is a software operation and its high frequency reduces system performance.


Topic Not Found

No matching topic was found. Some possible reasons and remedies are as follows:

  • The file (.chm) that contains the destination topic is not in the expected location.

    Remedy: Rerun the MSDN Library Setup.

  • The file (.chm) that contains the current topic or destination topic is out-of-date and the link is no longer valid.

    Remedy: Install the latest version of the MSDN Library.

  • The MSDN Library CD is not in the CD-ROM drive.

    Remedy: Insert the MSDN Library CD into the CD-ROM drive.