Using the Win32 API

This section provides an overview of the Microsoft Win32 Application Programming Interface (API), how it is organized, and some of the features that you can use in your Win32-based applications.

The Win32 API allows applications to exploit the power of the 32 bit Windows family of operating systems. The functions, structures, messages, macros, and interfaces form a consistent and uniform API for all of Microsoft's 32-bit platforms. Using the Win32 API, you can develop applications that run successfully on all platforms while still being able to take advantage of unique features and capabilities of any given platform.

Differences in the implementation of the programming elements depend on the capabilities of the underlying features of the platform. The most notable difference is that some functions carry out their tasks only on the more powerful platforms. For example, security functions are only available on the Windows NT operating system. Most other differences are system limitations, such as restrictions on the range of values or the number of items a given function can manage.

For a summary of Win32 differences on different platforms, see Win32 Platform Differences. For more information about system limitations in Windows 95, see Windows 95 System Limitations. For more information about system limitations in Win32s, see the Win32s Programmer's Reference.

The Win32 API can be grouped into these functional categories:

  • Window Management
  • Window Controls
  • Shell Features
  • Graphics Device Interface
  • System Services
  • International Features
  • Network Services


Window Management

The window management functions give applications the means to create and manage a user interface. You use the window management functions to create and use windows to display output, prompt for user input, and carry out the other tasks necessary to support interaction with the user. Most applications create at least one window.

Applications define the general behavior and appearance of their windows by creating window classes and corresponding window procedures. The window class identifies default characteristics, such as whether the window processes double clicks of the mouse buttons or has a menu. The window procedure contains the code that defines the behavior of the window, carries out requested tasks, and processes user input.

Applications generate output for a window using the GDI functions. Because all windows share the display screen, applications do not receive access to the entire screen. Instead, the system manages all output so that it is aligned and clipped to fit within the corresponding window. Applications can draw in a window in response to a request from the system or while processing input messages. When the size or position of a window changes, the system typically sends a message to the application requesting that it paint any previously unexposed area of its window.

Applications receive mouse and keyboard input in the form of messages. The system translates mouse movement, mouse button clicks, and keystrokes into input messages and places these messages in the message queue for the application. The system automatically provides a queue for each application. The application uses message functions to extract messages from the queue and dispatch them to the appropriate window procedure for processing.

Applications can process the mouse and keyboard input directly or let the system translate this low-level input into command messages by using menus and keyboard accelerators. You use menus to present a list of commands to the user. The system manages all the actions required to let the user choose a command and then sends a message identifying the choice to the window procedure. Keyboard accelerators are application-defined combinations of keystrokes that the system translates into messages. Accelerators typically correspond to commands in a menu and generate the same messages.

Applications often respond to command messages by prompting the user for additional information with dialog boxes. A dialog box is a temporary window that displays information or requests input. A dialog box typically includes controls — small, single-purpose windows — that represent buttons and boxes through which the user makes choices or enters information. There are controls for entering text, scrolling text, selecting items from a list of items, and so on. Dialog boxes manage and process the input from these controls, making this information available to the application so that it can complete the requested command.

You can share useful data, such as bitmaps, icons, fonts, and strings, by adding this data as "resources" to the file for an application or DLL. Applications retrieve the data by using the resource functions to locate the resources and load them into memory.

Window management functions provide other features related to windows, such as carets, the clipboard, cursors, hooks, icons, and menus.


Window Controls

The shell incorporates a number of controls that help give Windows its distinctive look and feel. Because these controls are supported by DLLs that are a part of the operating system, they are available to all applications. Using the common controls helps keep an application's user interface consistent with that of the shell and other applications. Because developing a control can be a substantial undertaking, using the common controls can also save you a significant amount of development time.

The common controls are a set of control windows that are supported by the common control library, COMCTL32.DLL. Like other controls, a common control is a child window that an application uses in conjunction with another window to perform I/O tasks. The common control DLL includes a programming interface that applications use to create and manipulate the controls as well as to receive user input from them.


Shell Features

The Win32 API contains a number of interfaces and functions that applications can use to enhance various aspects of the shell.

A namespace is a collection of symbols, such as file and directory names or database keys. The shell uses a single hierarchical namespace to organize all objects of interest to the user, including files, storage devices, printers, and network resources. The namespace is similar to the directory structure of a file system, except that the namespace contains objects other than files and directories.

A shortcut (also called a shell link) is a data object that contains information used to access another object located anywhere in the shell's namespace. A shortcut allows an application to access an object without having to know the current name and location of the object. Objects that can be accessed through shortcuts include files, folders, disk drives, printers, and network resources.

There are several ways to extend the shell. The system uses icons to represent files in the shell's namespace. By default, the system displays the same icon for all files that have the same filename extension. An icon handler can override the default and set the icon for a particular file. A context menu handler is a shell extension that modifies the contents of a context menu. The system displays a context menu when the user clicks or drags an object using mouse button 2. The context menu contains commands that apply specifically to the object that was clicked or dragged. Most context menus have a Properties command that displays the property sheet for the selected item. A property sheet contains information about an object in a set of overlapping windows called pages. A property sheet handler is a shell extension that adds pages to a system-defined property sheet or replaces pages in a Control Panel application's property sheet. A copy hook handler is a shell extension that approves or disapproves the moving, copying, deleting, or renaming of a file object.

The shell includes a Quick View command that allows the user to view the contents of a file without having to run the application that created it. A file viewer provides a user interface for viewing a file. The shell uses the filename extension to determine which viewer to run. You can provide file viewers for new file formats or replace an existing viewer with one that includes more functionality. A file viewer works in conjunction with a file parser, which provides the parsing needed to generate the Quick View of a file of a given type. You can provide additional file parsers to support new file types.


Graphics Device Interface

The graphics device interface (GDI) provides functions and related structures that an application can use to generate graphical output for displays, printers, and other devices. Using GDI functions, you can draw lines, curves, closed figures, paths, text, and bitmap images. The color and style of the items you draw depends on the drawing objects — that is, pens, brushes, and fonts — that you create. You can use pens to draw lines and curves, brushes to fill the interiors of closed figures, and fonts to write text.

Applications direct output to a given device by creating a device context (DC) for the device. The device context is a GDI-managed structure containing information about the device, such as its operating modes and current selections. An application creates a DC by using device context functions. GDI returns a device context handle, which is used in subsequent calls to identify the device. For example, using the handle, an application can retrieve information about the capabilities of the device, such as its technology type (display, printer, or other device) and the dimensions and resolution of the display surface.

Applications can direct output to a physical device, such as a display or printer, or to a "logical" device, such as a memory device or metafile. Logical devices give applications the means to store output in a form that is easy to send subsequently to a physical device. Once an application records output in a metafile, it can play that metafile any number of times, sending the output to any number of physical devices.

Applications use attribute functions to set the operating modes and current selections for the device. The operating modes include the text and background colors, the mixing mode (also called the binary raster operation) that specifies how colors in a pen or brush combine with colors already on the display surface, and the mapping mode that specifies how GDI maps the coordinates used by the application to the coordinate system of the device. The current selections identify which drawing objects are used when drawing output.


System Services

System services functions that give applications access to the resources of the computer and the features of the underlying operating system, such as memory, file systems, devices, processes, and threads. An application uses system services functions to manage and monitor the resources that it needs to complete its work. For example, an application uses memory management functions to allocate and free memory and uses process management and synchronization functions to start and coordinate the operation of multiple applications or multiple threads of execution within a single application.

System services functions provide access to files, directories, and input and output (I/O) devices. The file I/O functions give applications access to files and directories on disks and other the storage devices on a given computer and on computers in a network. These functions support a variety of file systems, from the FAT file system to the CD-ROM file system (CDFS) to NTFS.

System services functions provide methods for applications to share code or information with other applications. For example, you can make useful procedures available to all applications by placing these procedures in DLLs. Applications access these procedures by using DLL functions to load the libraries and retrieve the addresses of the procedures. Communications functions read from and write to communications ports as well as control the operating modes of these ports. There are several methods of interprocess communication (IPC), such as DDE, pipes, mailslots, and file mapping. For operating systems that provide security features, the security functions give applications access to secure data as well as protect data from intentional or unintentional access or damage.

System services functions provide access to information about the system and other applications. System information functions let applications determine specific characteristic about the computer, such as whether a mouse is present and what dimensions elements of the screen have. Registry and initialization functions let applications store application-specific information in system files so that new instances of the application or even other applications can retrieve and use the information.

System services functions provide features that applications can use to handle special conditions during execution, such as handling errors, logging events, and handling exceptions. There are features that applications can use to debug and improve performance. For example, debugging functions permit single-step control of the execution of other processes, and performance monitoring allows for detailing the path of execution through a process.

System services functions provice features you can use to create other types of applications, such as console applications and services.


International Features

These features are available to help you write applications for international markets. The Unicode character set uses 16-bit character values to represent characters used in computing, such as technical symbols, and many written languages. The national languages support (NLS) functions help you localize your application for international markets. The input method editor (IME) functions, available in Asian versions of Windows, help users enter text containing Unicode and DCBS characters.


Network Services

The network functions allow communication between applications on different computers on a network.

The network functions create and manage connections to shared resources, such as directories and network printers, on computers in the network.

The network interfaces include Windows Networking, Windows Sockets, NetBIOS, RAS, SNMP, the Net functions, and Network DDE. Windows 95 supports a subset of these functions.


Win32 Platform Differences

The following table contains a variety of Win32 API and operating system features and how each platform supports them. Bold text indicates an operating system feature, rather than an API feature.

Feature | Windows NT | Windows 95 | Windows 3.1 with Win32s
32-bit Coordinate System | Yes | No | No
32-bit Flat Memory model | Yes | Yes | Yes
3-D look | Yes | Yes | Yes
Asynchronous file I/O | Yes | No | No
Asynchronous input model | Yes | Yes | No
COMM | Yes | Yes | Via Universal Thunk
Common Controls |  |  |
Property sheet tabs | Yes | Yes | Yes
Drag list boxes | Yes | Yes | Yes
Toolbar | Yes | Yes | Yes
Status bar | Yes | Yes | Yes
Column heading | Yes | Yes | Yes
Spin buttons | Yes | Yes | Yes
Slider | Yes | Yes | Yes
Scrolling button indicator | Yes | Yes | Yes
Rich Edit Control | Yes | Yes | Yes
Progress indicator | Yes | Yes | Yes
Tree View | Yes | Yes | Yes
List View | Yes | Yes | Yes
Common Dialogs | Yes | Yes | Yes
Console Support | Yes | Except code page | No
Context menu on mouse button 2 | Yes | Yes | Yes
Enhanced metafiles | Yes | Yes | No
Event logging | Yes | No | No
File mapping | Yes | Yes | Yes
File merge/reconciliation | Yes | Yes | No
File Viewers | Yes | Yes | Not used
Image Color Matching (ICM) | Not yet | Yes | No
Long Filenames (LFN) | Yes | Yes | Won't appear
Multimedia API | Yes | Yes | Windows 3.1 level
Multiprocessor Machines | Yes | No | No
Named pipes | Yes | Client-side | Client-side
National Language Support (NLS) | Yes | Yes | Yes
Network DDE | Yes | Via Thunk | No
Non-Intel machines | Yes | No | No
Paths/Beziers | Yes | Limited | No
Pen | No | Yes | No
Plug and Play event aware | Won't get events | Yes | Won't get events
Preemptive multitasking | Yes | Yes | No
Print spooler | Yes | Except forms | No
Remote Access Services (RAS) | Yes | Yes | No
Remote Procedure Calls (RPC) | Yes | Yes | Via thunk
Security | Yes | No | No
Security (C2 certifiable) | Yes | No | No
Separate address space | Yes | Yes | No
Service control manager | Yes | No | No
Simple MAPI | Yes | Yes | Via Universal Thunk
Structured exception handling (SEH) | Yes | Yes | Yes
TAPI | Yes | Yes | No
Threads | Yes | Yes | No
Unicode | Yes | No | No
Universal Naming Convention (UNC) | Yes | Yes | Yes
User & GDI system resources | Virtually Unlimited | Expanded | Win3.1 limits
Windows 4.0 help | Yes | Yes | Context menu help won't appear
Windows Network (WNet) | Yes | Yes | Via Universal Thunk
Windows Sockets | Yes | Yes | Yes
World transforms | Yes | Scaling Only | No


A Generic Win32 Sample Application

This section introduces the source code components of a generic Win32-based application, named GENERIC. They closely resemble their counterparts in a generic 16-bit Windows-based application. This section assumes that you have used Win32-based applications and therefore are already familiar with windows, menus, and dialog boxes.

The GENERIC application described here consists of the following parts:

  • The entry-point function
  • The menu
  • The window procedure
  • The About dialog box

The complete code is shown in Source Code.


The Entry-Point Function

Every Win32-based application must have an entry-point function. The name commonly given to the entry point is the WinMain function.

As in most Win32-based applications, the WinMain function for the GENERIC application completes the following steps:

  • Registering the window class
  • Creating the main window
  • Entering the message loop


Registering the Window Class

Every window must have a window class. A window class defines the attributes of a window, such as its style, its icon, its cursor, the name of the menu, and the name of the window procedure.

The first step is to fill in a WNDCLASS structure with class information. Next, you pass the structures to the RegisterClass function. The GENERIC application registers the GenericAppClass window class as follows:

wc.lpszClassName = "GenericAppClass";
wc.lpfnWndProc = MainWndProc;
wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)( COLOR_WINDOW+1 );
wc.lpszMenuName = "GenericAppMenu";
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;

RegisterClass( &wc );

For more information on the menu, see The Menu. For more information on the window procedure, see The Window Procedure.


Creating the Main Window

You can create the window by calling the CreateWindow function. The GENERIC application creates the window as follows:

hWnd = CreateWindow( "GenericAppClass",
   "Generic Application",
   WS_OVERLAPPEDWINDOW|WS_HSCROLL|WS_VSCROLL,
   0,
   0,
   CW_USEDEFAULT,
   CW_USEDEFAULT,
   NULL,
   NULL,
   hInstance,
   NULL
);

The first parameter is the name of the class that we registered. The remaining parameters specify other window attributes. This call creates the window, but Windows does not display a window until the application calls the ShowWindow function. The GENERIC application displays the window as follows:

ShowWindow( hWnd, nCmdShow );


Entering the Message Loop

Once the main window is created and displayed, the WinMain function can being its primary task, which is to read messages from the application queue and dispatch them to the appropriate window.

Windows does not send input directly to an application. Instead, it places all mouse and keyboard input from the user into a message queue, along with messages posted by Windows and other application. The application must read the message queue, retrieve the messages, and dispatch them so that the window procedure can process them.

The GENERIC application uses the following message loop:

while( GetMessage( &msg, NULL, 0, 0 ) ) {
   TranslateMessage( &msg );
   DispatchMessage( &msg );
}

The GetMessage function retrieves a message from the queue. The DispatchMessage function sends each message to the appropriate window procedure. The TranslateMessage function translates virtual-key message into character messages. In GENERIC, this is necessary to implement menu access keys.


The Menu

Most applications include a menu to provide a means for the user to select commands. The most common way to create a menu is to define it as a resource in the resource-definition file. The GENERIC application has a single menu, named Help, with a single command, About. The resource is defined as follows:

GenericAppMenu MENU
{
   POPUP "&Help"
   {
      MENUITEM "&About",         IDM_ABOUT
   }
}

The name of the menu resource is specified when registering the window class.

Selecting the About command causes GENERIC to display the about dialog box.


The Window Procedure

Every window must have a window procedure. The name of the window procedure is user-defined. The GENERIC application uses the following window procedure for the main window:

LRESULT WINAPI MainWndProc( HWND, UINT, WPARAM, LPARAM );

The WINAPI modifier is used because the window procedure must be declared with the standard call calling convention.

The window procedure receives messages from Windows. These may be input messages or window-management messages from Windows. You can optionally handle a message in your window procedure or pass the message to Windows for default processing by calling the DefWindowProc function. The GENERIC application processes the WM_PAINT, WM_COMMAND, and WM_DESTROY messages, using a switch statement that is structured as follows:

switch( msg ) {
      case WM_PAINT:
      ...
      case WM_COMMAND:
      ...
      case WM_DESTORY:
      ...
      default:
         return( DefWindowProc( hWnd, msg, wParam, lParam ));

The WM_PAINT message indicates that you should redraw what's in all or part of your application's window. Use the BeginPaint function to get a handle to a device context, then use the device context for drawing within the application's window, with functions like TextOut. Use EndPaint to release the device context. The GENERIC application displays a text string, "Hello, World!", in the window using the following code:

case WM_PAINT:
      hDC = BeginPaint( hWnd, &ps );

      TextOut( hDC, 10, 10, "Hello, World!", 13 );

      EndPaint( hWnd, &ps );
      break;

The WM_COMMAND message indicates that a user has selected a command item from a menu. The GENERIC application uses the following code to check if its About menu item has been selected:

case WM_COMMAND:
         switch( wParam ) {
            case IDM_ABOUT:
            ...
            break;
         }

Most window procedures process the WM_DESTROY message. Windows sends this message to the window procedure immediately after destroying the window. The message gives you the opportunity to finish processing and post a WM_QUIT message in the application queue. The GENERIC application handles the WM_DESTROY message as follows:

case WM_DESTROY:
   PostQuitMessage( 0 );
   break;


The About Dialog Box

A dialog box is a temporary window that displays information or prompts the user for input. The GENERIC application includes an About dialog box. Every application should include an About dialog box. The dialog box displays such information as the application's name and copyright information.

You create and display a dialog box by using the DialogBox function. This function takes a dialog box template and creates a dialog box.

The GENERIC application includes the following dialog box template in the resource-definition file:

AboutDlg DIALOG FIXED 6, 21, 198, 99
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "About Generic"
FONT 8, "MS Shell Dlg"
BEGIN
    DEFPUSHBUTTON   "&OK", IDOK, 72, 74, 40, 14
    LTEXT           "Generic Application", 104, 45, 14,
                    128, 8
    LTEXT           "Written as a sample", 105, 45, 35, 59, 8
    LTEXT           "Microsoft Corporation", 106, 45, 45, 98, 8
    LTEXT           "Copyright (c) 1996", 107, 45,
                    54, 138, 8
END

The name of the source is specified as AboutDlg. For more information, see Dialog Resource.

When the user clicks About from the Help menu, the following code in the window procedure displays the About dialog box:

case WM_COMMAND:
   switch( wParam ) {
      case IDM_ABOUT:
         DialogBox( ghInstance, "AboutDlg", hWnd, (DLGPROC)
                    AboutDlgProc );
      break;
   }
break;

The last parameter is a pointer to a dialog box procedure. It has the following prototype.

LRESULT WINAPI AboutDlgProc( HWND, UINT, WPARAM, LPARAM );

A dialog box procedure is similar to a window procedure, but usually processes only dialog initialization and user-input messages. The GENERIC application contains the following message processing code:

switch( uMsg ) {
   case WM_INITDIALOG:
      return TRUE;
   case WM_COMMAND:
      switch( wParam ) {
         case IDOK:
            EndDialog( hDlg, TRUE );
            return TRUE;
      }
   break;
}

return FALSE;


Source Code

The GENERIC application consists of the following files:

  • GENERIC.C
  • GENERIC.H
  • GENERIC.RC
  • GENERIC.DLG


GENERIC.C

GENERIC.C contains code for the GENERIC application. It includes GENERIC.H.

/********************************************************************\
*  generic.c: Source code for generic                                *
*                                                                    *
*  Comments: Generic Win32-based Application                         *
*                                                                    *
*  Functions:                                                        *
*     WinMain      - Application entry point                         *
*     MainWndProc  - main window procedure                           *
*     AboutDlgProc - dialog procedure for About dialog               *
*                                                                    *
*                                                                    *
\********************************************************************/

/*********************  Header Files  *********************/

#include <windows.h>
#include "generic.h"

/*********************  Prototypes  ***********************/

LRESULT WINAPI MainWndProc( HWND, UINT, WPARAM, LPARAM );
LRESULT WINAPI AboutDlgProc( HWND, UINT, WPARAM, LPARAM );

/*******************  Global Variables ********************/

HANDLE ghInstance;

/********************************************************************\
*  Function: int PASCAL WinMain(HINSTANCE, HINSTANCE, LPSTR, int)    *
*                                                                    *
*   Purpose: Initializes Application                                 *
*                                                                    *
*  Comments: Register window class, create and display the main      *
*            window, and enter message loop.                         *
*                                                                    *
*                                                                    *
\********************************************************************/

int PASCAL WinMain( HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpszCmdLine,
    int nCmdShow )
{
   WNDCLASS wc;
   MSG msg;
   HWND hWnd;

   if( !hPrevInstance )
   {
      wc.lpszClassName = "GenericAppClass";
      wc.lpfnWndProc = MainWndProc;
      wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
      wc.hInstance = hInstance;
      wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
      wc.hCursor = LoadCursor( NULL, IDC_ARROW );
      wc.hbrBackground = (HBRUSH)( COLOR_WINDOW+1 );
      wc.lpszMenuName = "GenericAppMenu";
      wc.cbClsExtra = 0;
      wc.cbWndExtra = 0;

      RegisterClass( &wc );
   }

   ghInstance = hInstance;

   hWnd = CreateWindow( "GenericAppClass",
      "Generic Application",
      WS_OVERLAPPEDWINDOW|WS_HSCROLL|WS_VSCROLL,
      0,
      0,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      NULL,
      NULL,
      hInstance,
      NULL
   );

   ShowWindow( hWnd, nCmdShow );

   while( GetMessage( &msg, NULL, 0, 0 ) ) {
      TranslateMessage( &msg );
      DispatchMessage( &msg );
   }

   return msg.wParam;
}

/********************************************************************\
* Function: LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM) *
*                                                                    *
*  Purpose: Processes Application Messages                           *
*                                                                    *
* Comments: The following messages are processed                     *
*                                                                    *
*           WM_PAINT                                                 *
*           WM_COMMAND                                               *
*           WM_DESTROY                                               *
*                                                                    *
*                                                                    *
\********************************************************************/

LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam,
   LPARAM lParam )
{
   PAINTSTRUCT ps;
   HDC hDC;

   switch( msg ) {

/**************************************************************\
*     WM_PAINT:                                                *
\**************************************************************/

      case WM_PAINT:
         hDC = BeginPaint( hWnd, &ps );

         TextOut( hDC, 10, 10, "Hello, World!", 13 );

         EndPaint( hWnd, &ps );
         break;

/**************************************************************\
*     WM_COMMAND:                                              *
\**************************************************************/

      case WM_COMMAND:
         switch( wParam ) {
            case IDM_ABOUT:
               DialogBox( ghInstance, "AboutDlg", hWnd, (DLGPROC)
                          AboutDlgProc );
            break;
         }
      break;

/**************************************************************\
*     WM_DESTROY: PostQuitMessage() is called                  *
\**************************************************************/

      case WM_DESTROY:
         PostQuitMessage( 0 );
         break;

/**************************************************************\
*     Let the default window proc handle all other messages    *
\**************************************************************/

      default:
         return( DefWindowProc( hWnd, msg, wParam, lParam ));
   }

   return 0;
}

/********************************************************************\
* Function: LRESULT CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM)*
*                                                                    *
*  Purpose: Processes "About" Dialog Box Messages                    *
*                                                                    *
* Comments: The About dialog box is displayed when the user clicks   *
*           About from the Help menu.                                *
*                                                                    *
\********************************************************************/

LRESULT CALLBACK AboutDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
   switch( uMsg ) {
      case WM_INITDIALOG:
         return TRUE;
      case WM_COMMAND:
         switch( wParam ) {
            case IDOK:
               EndDialog( hDlg, TRUE );
               return TRUE;
         }
      break;
   }

   return FALSE;
}


GENERIC.H

GENERIC.C contains header information for the GENERIC application. It is included in GENERIC.C and GENERIC.RC.

/*************************************************************\
* generic.h: Header file for Generic                          *
*                                                             *
*                                                             *
\*************************************************************/

/******* Menu Defines *******/

#define IDM_ABOUT      1000


GENERIC.RC

GENERIC.RC contains resource information for the GENERIC application. The dialog resources are included in GENERIC.DLG.

/*************************************************************\
* generic.rc: Resource script for Generic                     *
*                                                             *
*                                                             *
\*************************************************************/

#include <windows.h>
#include "generic.h"
#include "generic.dlg"

GenericAppMenu MENU
{
   POPUP "&Help"
   {
      MENUITEM "&About",         IDM_ABOUT
   }
}


GENERIC.DLG

GENERIC.DLG defines the About dialog box for the GENERIC application. This file is included in GENERIC.RC.

/*************************************************************\
* generic.dlg: Dialogs for Generic                            *
*                                                             *
*                                                             *
\*************************************************************/

1 DLGINCLUDE "generic.h"

AboutDlg DIALOG FIXED 6, 21, 198, 99
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "About Generic"
FONT 8, "MS Shell Dlg"
BEGIN
    DEFPUSHBUTTON   "&OK", IDOK, 72, 74, 40, 14
    LTEXT           "Generic Application", 104, 45, 14,
                    128, 8
    LTEXT           "Written as a sample", 105, 45, 35, 59, 8
    LTEXT           "Microsoft Corporation", 106, 45, 45, 98, 8
    LTEXT           "Copyright (c) 1996", 107, 45,
                    54, 138, 8
END


Building Applications Using WIN32.MAK

The makefiles that accompany code samples in the Platform SDK give good examples of build processes that rely on NMake.exe. Each of them includes WIN32.MAK, which defines many common macros you can use to build 32-bit applications for Windows NT and Windows 95.

This section describes how 32-bit applications and dynamic-link libraries (DLLs) for Windows can be built using the Platform SDK and your development tools. It describes makefile components you may need and includes information on using the C run-time libraries.

WIN32.MAK

The WIN32.MAK file defines macros that can be used to simplify your own makefiles for use with Microsoft development tools. These macros help assure that you have chosen the correct options for the following tasks:

  • Setting Targets
  • Compiling Source Files
  • Linking
  • Building DLLs
  • Using the C Run-Time Library

WIN32.MAK should be included in your makefile as follows:

!include <win32.mak>

You can learn a good deal by examining the contents of WIN32.MAK, located in the MSTOOLS\INCLUDE subdirectory.

The following table summarizes the steps used to build a Win32-based application or DLL:

Step | Tool
Compile C and C++ source-language files into object files. | C/C++ compiler included with your development tools.
Create and edit resources. Doing so may also create include (.H) files which define useful constants. | Dialog Editor, Image Editor, and Font Editor included with the SDK or equivalent development tools.
Compile resource scripts into linkable resource files. | Resource Compiler included with the SDK or your development tools.
Create import libraries for each DLL. | Library manager included with your development tools.
Link the object modules, resources, standard libraries, and import libraries (for an executable using DLLs) to produce an executable module. | Linker included with your development tools.
Tune your application. | Performance tools and Working Set Tuner included with the SDK.


Setting Targets

WIN32.MAK includes the following macros that control the type of target that is built. Set these macros in your makefile prior to including WIN32.MAK or set them as environment variables.

  • APPVER

    Specifies the version of the application. The value includes major and minor versions, (i.e. 3.51 or 4.0). It is used for checking version dependencies and for marking the executable with version information.

  • TARGETOS

    Specifies the operating system. The value can be WIN95, WINNT, or BOTH. It is used for checking platform dependencies.

  • TARGETLANG

    Specifies the language. The value can be Japanese. The default value is the system locale.

In addition, you may set one of these values to 1 on the NMAKE command line or as an environment variable.

  • NODEBUG

    Specifies no debugging information should be included in the output files.

  • PROFILE

    Specifies that information for the profiler should be included in the output files.

  • TUNE

    Specifies that information for the working set tuner (WST) should be included in the output files.

For example, the following command line specifies that no debugging information should be included in the output files:

nmake NODEBUG=1


Compiling Source Files

WIN32.MAK includes the following macros to simplify compilation of C/C++ source files:

  • $(CC)

    This macro is used to invoke the compiler. It expands to the following:

    cl
  • $(CFLAGS)

    This macro is used for common compiler flags. It is platform dependent. On x86 machines, it includes the following flags:

    -c -W3 -D_X86=1
  • $(CDEBUG)

    This macro is used for debugging, profiling, and tuning compiler flags. When specifying debug, but no profiling or tuning, it expands to the following flags:

    -Z7 -Od

Use one of the following three macros if you are using the C run-time library:

  • $(CVARS)

    This macro is used for single-threaded applications. It expands to the following flags:

    -DWIN32 -DNULL=0
  • $(CVARSMT)

    This macro is used for multithreaded applications. It expands to the following flags:

    -DWIN32 -DNULL=0 -D_MT
  • $(CVARSDLL)

    This macro is used for applications that use the CRT in a DLL. It expands to the following flags:

    -DWIN32 -DNULL=0 -D_MT -D_DLL

The following example shows how you can compile your source files using these macros:

generic.obj: generic.c
    $(cc) $(cdebug) $(cflags) $(cvarsdll) $*.c

WIN32.MAK includes the following macros to simplify compilation of resource-definition files:

  • $(RC)

    This macro is used to invoke the resource compiler. It expands to the following:

    rc
  • $(RCFLAGS)

    This macro is used for common flags. It expands to the following flags:

    -r
  • $(RCVARS)

    This macro is used for other flags. It expands to the following flags:

    -DWIN32 -DWINVER=0x0400

The following example shows how you can compile your resource-definition file using these macros:

generic.res: generic.rc generic.h generic.dlg
    $(rc) $(rcvars) $(rcflags) $*.rc


Linking

WIN32.MAK contains the following macros to simplify linking applications:

  • $(LINK)

    This macro is used to invoke the linker. It expands to the following flags:

    link
  • $(LDEBUG)

    This macro is used for for specifying debugging, profiling, and tuning linker flags. When specifying debug, but no profiling or tuning, it expands to the following flags:

    -debug:full -debugtype:cv

Use one of the following flags, depending on whether you are building a console application or a GUI application:

  • $(CONLFLAGS)

    This macro is used for console applications. It is platform dependent. On x86 machines, it expands to the following flags:

    -/NODEFAULTLIB /INCREMENTAL:NO /PDB:NONE /RELEASE /NOLOGO
-align:0x1000 -subsystem:console,4.0 -entry:mainCRTStartup
  • $(GUIFLAGS)

    This macro is used for GUI applications. it is platform dependent. On x86 machines, it expands to the following flags:

    -/NODEFAULTLIB /INCREMENTAL:NO /PDB:NONE /RELEASE /NOLOGO
-align:0x1000 -subsystem:windows,4.0 -entry:WinMainCRTStartup

Notice that these macros provide entry points in the CRT libraries. These CRT entry points will call your entry-point function (main or WinMain).

Use one of the following flags if you are using the single-threaded CRT:

  • $(CONLIBS)

    This macro is for console applications using LIBC.LIB. It expands to the following list of libraries:

    LIBC.LIB OLDNAMES.LIB KERNEL32.LIB ADVAPI32.LIB
  • $(GUILIBS)

    This macro is used for GUI application using LIBC.LIB. It expands to the following list of libraries:

    LIBC.LIB OLENAMES.LIB KERNEL32.LIB ADVAPI32.LIB USER32.LIB GDI32.LIB COMDLG32.LIB WINSPOOL.LIB

Use one of the following flags if you are using the multithreaded CRT:

  • $(CONLIBSMT)

    This macro is for console applications using LIBCMT.LIB. It expands to the following list of libraries:

    LIBCMT.LIB OLDNAMES.LIB KERNEL32.LIB ADVAPI32.LIB
  • $(GUILIBSMT)

    This macro is used for GUI application using LIBCMT.LIB. It expands to the following list of libraries:

    LIBCMT.LIB OLDNAMES.LIB KERNEL32.LIB ADVAPI32.LIB USER32.LIB GDI32.LIB COMDLG32.LIB WINSPOOL.LIB

Use one of the following flags if you are using the CRT in a DLL:

  • $(CONLIBSDLL)

    This macro is for console applications using MSVCRT.LIB. It expands to the following list of libraries:

    MSVCRT.LIB OLDNAMES.LIB KERNEL32.LIB ADVAPI32.LIB
  • $(GUILIBSDLL)

    This macro is used for GUI application using MSVCRT.LIB. It expands to the following list of libraries:

    MSVCRT.LIB OLDNAMES.LIB KERNEL32.LIB ADVAPI32.LIB USER32.LIB GDI32.LIB COMDLG32.LIB WINSPOOL.LIB

The following example links the object files and libraries to produce the application executable file. Note that the resource file (generic.res) is linked along with the object file (generic.obj).

generic.exe : generic.obj generic.res
    $(link) $(ldebug) $(guilflags) generic.obj generic.res \
        $(guilibsdll) -out:generic.exe


Building DLLs

To build a DLL, use the macros defined for Linking. WIN32.MAK also includes the following macros to simplify linking DLLS:

  • $(IMPLIB)

    This macro is used to invoke the library manager. It expands to the following flags:

    lib
  • $(DLLENTRY)

    This macro is used as a suffix for the entry-point function. It is platform dependent. It defines to nothing on MIPS, Alpha, and PPC machines. It expands to the following flags on x86 machines:

    @12
  • $(DLLLFLAGS)

    This macro is used for DLLs. It expands to the following flags:

    -/NODEFAULTLIB /INCREMENTAL:NO /PDB:NONE /RELEASE /NOLOGO
-align:0x1000 -entry:_DllMainCRTStartup$(DLLENTRY) -dll

The following example illustrates how to create the import library for a DLL. The import library is linked with the application that uses this DLL.

mydll.lib: mydll.def mydll.obj
    $(implib) -machine:$(CPU) -def:mydll.def mydll.obj -out:mydll.lib

The following example links the DLL:

mydll.dll : mydll.obj
    $(link) $(ldebug) $(dlllflags) -base:0x1C000000 mydll.obj \
        $(conlibsdll) -out:mydll.dll


Using the C Run-Time Library

C Run-Time (CRT) libraries are not distributed with the Platform SDK. Many vendors distribute forms of CRT libaries under different names. These name differences can be encapsulated in WIN32.MAK.

The following sections describe specifically how to use the different forms of Microsoft's C Run-time Library when building your application.

  • Calling the C Run-Time Library from a DLL
  • Mixing Library Types

Microsoft Visual C++ contains three forms of the CRT:

LIBC.LIB
Statically linked library for single-threaded applications.
LIBCMT.LIB
Statically linked library that supports multi-threaded applications.
MSVCRT.LIB
Import library for the CRT in a DLL that also supports multi-threaded applications.

Note If you would like to avoid linking in the CRT, compile your source files with the -Qlfdiv- flag, do not call the CRT functions, do not call any math routines, and do not specify an entry point in the CRT with the -entry linker option.


Calling the C Run-Time Library from a DLL

When linking a DLL with any of the C run-time libraries, you must specify the following the entry point for the DLL.

-entry:_DllMainCRTStartup$(DLLENTRY)

This entry point is exported from the C run-time libraries and performs necessary initialization. The $(DLLFLAGS) macro in WIN32.MAK includes the -entry flag shown above.

DllMainCRTStartup will call your entry point if you name it DllMain and export it from your DLL. Therefore, your DLL entry-point function will look something like this:

BOOL WINAPI DllMain( HINSTANCE hinstDLL,
                     DWORD fdwReason,
                     LPVOID lpReserved )
{

   if( fdwReason==DLL_PROCESS_ATTACH || fdwReason==DLL_THREAD_ATTACH )
   ...
   if( fdwReason==DLL_PROCESS_DETACH || fdwReason==DLL_THREAD_DETACH )
   ...

   return( TRUE );

}

For more information, see DllMain.


Mixing Library Types

If your DLL is linked with MSVCRT.LIB, any modules that call your DLL should also be linked with MSVCRT.LIB. Otherwise, unpredictable results can occur, because the module and the DLL have separate copies of all CRT functions and global variables. To avoid problems, link both the executable and the DLL with MSVCRT.LIB. This allows both the executable and the DLL to use the common set of functions and data contained in MSVCRT.DLL. C run-time data such as stream handles can then be shared by both the executable and the DLL.

If you must mix library types, be sure to use the following guidelines:

  • CRT file handles may only be used by the module that created them.
  • FILE pointers may only be used by the module that created them.
  • Memory allocated with the CRT may only be freed or reallocated by the module that allocated.

If a DLL is linked with LIBC.LIB, and the DLL may be called by a multi-threaded application, multiple threads running in this DLL at the same time will not be supported. This may cause unpredictable results. Therefore, if there is a possibility that the DLL will be called by multi-threaded programs, be sure to link it with one of the libraries that support multi-threaded programs (LIBCMT.LIB or MSVCRT.LIB).


Improving Application Performance for Windows NT

Improving Application Performance on Windows NT

This overview provides some guidelines and hints to help you improve application performance on Windows NT.

The sophisticated virtual memory manager in Windows NT 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 and Windows 95 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 can address 4 gigabytes of memory. Each application running on Windows NT 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 earlier version of 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 Windows NT 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 0xffffffff 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 machines 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, opening a file uses more resources. Therefore, on Windows NT, 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 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 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 reduced scrolling time in a console window by 30% when it was implemented during the development of Windows NT.

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 machine 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, 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, 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 than

select(grey);
patblt(...);
patblt(...);
patblt(...);
select(black);
patblt(...);
patblt(...);
patblt(...);

In Windows NT, 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. 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 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, 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, it is easy it is to get it to run on RISC versions of Windows NT. This is because there are virtually no processor dependencies in the Win32 API.

However, an application’s performance can suffer on a RISC machine if its data is not properly aligned. To handle this problem, align the data in your source for both RISC and non-RISC machines. You want to assure that you have DWORDs on DWORD boundaries, and LARGE_INTEGERS 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.


Installing Applications

This article describes a standard set of guidelines for installing Win32-based applications.


About Installing Applications

The purpose of the guidelines described in this article is to enable all application developers to support the same general method of application installation. The prime benefit is for users, many of whom have said they prefer a consistent installation method so that they do not need to learn a different method with each new software purchase. These guidelines also benefit the application developer by helping to standardize the organization and management of application files, thereby making initial installations, updates, and application removals easier. To ensure that your installation procedure follows these guidelines use Microsoft Installer Technology.


Installation Program

The installation program plays the primary role in carrying out application installation. The program retrieves information from the user and the computer and installs the files and information needed to run the application successfully. Every installation program carries out these basic steps:

  1. Determines the user's hardware and software configuration and available disk space.
  2. Copies application executable and data files to the appropriate directories on the hard disk.
  3. Sets up the execution environment for the application by modifying existing files and adding entries to the registry.

A Microsoft Installer Technology installation program (or a companion program) should also be prepared to update or remove an already installed application.

By using Microsoft installer technology, you can easily accomplish all of these steps. There are a variety of third-party tools available to make creating a Microsoft installer technology installation easy.

Windows also provides an Add/Remove Programs application in Control Panel that helps guide the user through starting the installation, update, or removal process. When the user chooses to install an application, Add/Remove Programs automatically checks the floppy and compact disc read-only memory (CD-ROM) drives for installation programs, searching for filenames such as SETUP.EXE and INSTALL.EXE. If a file is found and the user agrees to finish the installation, Add/Remove Programs starts the program and exits. After that, the started program is responsible for guiding the user through the rest of the installation process.


Designing the User Interface

Your installation program should use the standard Windows graphical user interface. It should present users with options and status. Sections of The Windows Interface Guidelines for Software Design describe how to design an application that is consistent with the look and feel of the Windows shell. It will also give you information about easy-to-implement features that will add value to your application and make use of new usability functionality in the shell.

To further increase the value of your application and reduce your customer's total cost of ownership (TCO) use Microsoft Installer Technology as your installation and component management technology.

Your installation program should always offer setup options. The following options are recommended.

Typical setup | Installs the application with all of the most common settings and copies the most commonly used files. This should be the default setup option.
Compact setup | Copies the fewest number of files needed to operate your application. This option is useful for laptops and computers on which disk space is at a premium.
Custom setup | Allows the user to determine the details of the installation, such as the directories to receive the files and the application features to enable. This option, which is typically used by the power user, should also include an option to set up components left out during a typical or compact setup.
Silent setup | Runs setup without user interaction. This should just be a command line option so that your installation program can be run within a batch script.

Your installation program should always supply defaults. In particular, it should supply a common response to every option so that all the user has to do is press the enter key.

Your installation program should never ask the user to install a disk more than once and should make the computer beep when it is time for the user to insert a new disk.

Your installation program should always include a progress indicator to show users how far along they are in the setup procedure.

Your installation program should always give the user a chance to cancel the setup process before it is finished. Your program should keep a log of files that have been copied and settings that have been made so that it can clean up a canceled installation. If the installation is canceled, your program should remove any registry entries it may have made, remove any shortcuts it may have added to the desktop, and delete any files it may have copied onto the user's hard disk. Microsoft Installer Technology provides a framework to implement all of these aspects of a good installation program.


Determining the Configuration

Your installation program should determine the hardware and software configuration of the user's computer before copying files and setting the environment. It is important for the installation program to verify that everything needed to successfully run the application is available. For example, if your application depends on specific hardware or software, your installation program should make sure the hardware or software is present. If it is not, the program should notify the user immediately and recommend a course of action. By using Microsoft Installer Technology, you can do this simply and automatically.

Your installation program should always tell the user how much disk space is needed. For custom setup, the installation program should adjust the "space needed" figure as the user selects and deselects options. Your installation program should verify that enough disk space is present for the options that the user selects. If there is not enough free space, the program should notify the user but give the user the option to override the warning. Microsoft installer technology provides a comprehensive method for determining available disk space and required disk space.

Your installation program should always determine whether any of the files to be installed are already on the hard disk. This is especially important for shared files, such as commonly used dynamic-link libraries (DLL). If the files already exist, your installation program should check the version number to ensure that it is not replacing a file with an older version. In other words, the installation program should always make sure the most recent version of a file is installed on the user's disk. Microsoft installer technology has a configuration database that keeps track of all of the components and files needed for all applications that use Microsoft installer technology on a particular computer. This makes it easy to check component versions and ensure that shared components are installed properly.


Copying Files

Your installation program should copy all necessary executable and data files to the appropriate directories. It should never copy these files to the WINDOWS or SYSTEM directories. Instead, it should create a directory in the Program Files directory and copy its files there. If the Program Files directory does not exist on the root of the hard disk, your installation program should create it.

It is recommended that your installation program use a long filename for the directory, such as the application name or another descriptive and unique name. Your program should copy the main executable file for your application and any other executable or data files that the user may want to open directly to the newly created directory. For example, if your application's name is "My Wizzy Application.Exe", your installation program should create the \Program Files\My Wizzy Application directory, and copy My Wizzy Application.Exe to that directory.

If you have any other executable or data files, such as .DLL and .HLP files that are specific to your application, your installation program should create a subdirectory, named System, in your application's directory. It should copy the remaining files (except shared files) to this new directory. For example, if your application has a DLL named MWASUP.DLL, your installation program should create the \Program Files\My Wizzy Application\System directory and copy the DLL there.

If any of your executable or data files are shared, your installation program needs to copy the files to yet another directory, depending on how widely the file is to be shared. A file is system-wide shared if many applications from different vendors use it. For example, the VBRUN300.DLL file is a system-wide shared file, because it is used by any application built with Visual Basic. A file is a shared file if it is shared by a set of applications from the same vendor. A common example of this would be an office suite that might use the same drawing program for its word processor as it does for its spreadsheet.

Your installation program should copy all system-wide shared files to the Windows SYSTEM directory. If a given file already exists in this directory, the program should overwrite it with your application file only if your file is a more recent version. The GetFileTime, GetFileVersionInfo, and GetFileInformationByHandle functions can be used to determine which file is more recent. After copying a DLL file, if your installation program does not use Microsoft Installer Technology, it should increment the usage counter for the DLL in the registry. For more information about the usage counter, see Adding Entries to the Registry. Microsoft installer technology has a configuration database that keeps track of all of the components and files needed for all applications that use Microsoft installer technology on a particular computer. This makes it easy to manage shared components.

Your installation program should copy all shared files to a System directory in the \Program Files\Common Files directory. If the directory does not exist, the installation program should create it. Again, it is recommended that your program use a descriptive and unique name. For example, if there is a shared file named My Wizzy Speller.Exe, your program should create a directory named \Program Files\Common Files\System and copy the file there. The location of the Program Files and Common Files directories is registered (using the macro REGSTR_PATH_SETUP) in the HKEY_LOCAL_MACHINE root under the SOFTWARE\Microsoft\Windows\CurrentVersion key. The value names are ProgramFilesDir and CommonFilesDir.

When your installation program installs applications on computers running Microsoft® Win32s® with Windows version 3.x, it needs to be aware that the system does not support long filenames. Your installation program will need to use the short 8.3 filename equivalent for Program Files and Common Files, which is Progra~1 and Common~1, respectively.


Replacing DLLs in Memory

Installation programs often need to replace old .DLL files with new versions. However, what if the DLL is already in memory? It is still possible to replace the DLL. The method you use to replace DLLs in memory depends on the platform. Microsoft Installer Technology, provides a mechanism for handling files in use.

Windows NT:

To replace DLLs already loaded in memory, use the MoveFileEx function.

Windows 95:

Windows 95 does not allow a .DLL file to be replaced if the DLL is currently loaded into memory. To solve this problem, your installation program must copy the new .DLL files to the user's machine, giving each new .DLL file a temporary name that is different from that of the corresponding old .DLL file. Your installation program must also copy a file called WININIT.INI to the user's machine. The WININIT.INI file is processed by the WININIT.EXE program when the system is restarted, before any DLLs are loaded. The WININIT.INI file specifies the destination path and filename for each new DLL.

The WININIT.INI file contains a [rename] section that specifies the source and destination path and filenames for the new DLLs. The entries in the [rename] section have the following syntax.

DestinationFileName=SourceFileName

The following syntax is used to delete a file.

NUL=SourceFileName

The following example shows a [rename] section from a WININIT.INI file.

[rename]
C:\WINDOWS\Fonts\arial.ttf=C:\WINDOWS\Fonts\arial.win
C:\WINDOWS\SYSTEM\advapi32.dll=C:\WINDOWS\SYSTEM\advapi32.tmp

When the system is restarted, it searches for a WININIT.INI file and, if it finds one, runs WININIT.EXE on the file. After processing the file, WININIT.EXE renames it to WININIT.BAK.

The DestinationFileName and SourceFileName must both be short (8.3) names instead of long filenames because WININIT.EXE is a non-Windows application and runs before the protected mode disk system is loaded. Because long filenames are only visible when the protected mode disk system is loaded, WININIT.EXE won't see them, and therefore, won't process them.


Installing Fonts

By carrying out these steps, you can write a single font installation routine that works for both Windows NT and Windows 95:

If you use Microsoft Installer Technology, fonts are registered automatically.

  1. Determine whether the platform is Windows 95 or Windows NT. This distinction is important because Windows 95 allows a shared network installation where most system files, including fonts, are stored on a centrally managed server. To determine the platform, look in the following registry location for a "SharedDir" value.
    HKeyLocalMachine\Software\Microsoft\Windows\CurrentVersion\Setup

    The data value of "SharedDir" is the UNC name of the server and sharepoint of the shared directory. In most cases, a shared directory is marked as read-only by the system administrator, so your installation program should also check to see if it can write to this location. If it cannot, it should let the user install the fonts in a different location, or stop the setup process.

  2. Check whether the TrueType® font being installed is already present on the system by using the EnumFontFamilies function. If that font is present, the program should check to see if its version is newer by matching the installed font name with the filename on the disk. The font name is stored in the following registry location for both Windows 95 and Windows NT.
    HKeyLocalMachine\Software\Microsoft\Windows\CurrentVersion\Fonts

    The subkeys in this registry location contain the full name of the font file as the value key, followed by the filename of the .TTF file as the key data. If the filename in the registry is just a filename with no path information, the font is installed in the \WINDOWS\FONTS directory for Windows 95 or the \WINDOWS\SYSTEM directory for Windows NT. Because TrueType font files do not carry a version resource, your program will need to retrieve the version string from the 'name' table in the .TTF file.

    • Before copying the .TTF file to the appropriate directory, the installation program should check to see if the filename already exists in that directory. If it does, the program should rename your .TTF file to some other name, perhaps by appending a number to the end of the basename.
    • After copying the .TTF file to the user's disk, the installation program should inform the system that it wants the font to be available. The program should pass it the .TTF filename directly by using the AddFontResource function. Windows 95 and Windows NT do not require the creation of .FOT files.
    • To make the font installation permanent, the installation program should add the font name and filename to the registry by writing both of the values to the following registry location.
      HKeyLocalMachine\Software\Microsoft\Windows\CurrentVersion\Fonts


Removing an Application

Your installation program can direct the Add/Remove Programs application in Control Panel to list your application as an application that can be "automatically removed."

If you use Microsoft Installer Technology, there is no need to ensure that your application can be easily uninstalled. Microsoft installer technology has enough information about your application that it can uninstall it without an uninstall application.

If you don't use Microsoft installer technology, you can present an uninstall program by adding entries to the following registry key:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\application-name

Note that application-name may not exceed 63 characters. You can use a GUID (38 characters long) to ensure that your key name will be unique.

The entries are as follows:

DisplayName=product-name
UninstallString=full-path-to-program command-line-parameters

Add/Remove Programs displays the product name specified by the DisplayName value in its list of applications that can be removed. Windows uses the value specified by the UninstallString value to start the uninstall program to carry out the removal of the application. This string needs to completely specify the command-line parameters needed to execute the uninstall program and remove the application. A full path is required. Both the DisplayName and UninstallString values must be complete, or Add/Remove Programs will not list the application.

Windows needs to know when the removal of the application is done, so it requires the UninstallString value to specify the uninstall program that actually carries out the removal. A batch file or other program that starts the removal program should not be specified.

The registry locations are defined as constants for C programmers in the REGSTR.H header file. Descriptions of the macros follow.

REGSTR_PATH_UNINSTALL | Path to uninstall branch
REGSTR_VAL_UNINSTALLER_DISPLAYNAME | DisplayName
REGSTR_VAL_UNINSTALLER_COMMANDLINE | UninstallString

The uninstall program must display a user interface that informs the user that the removal process is taking place. Your uninstall program should provide a silent option that allows the user to run it remotely. The uninstall program should also display clear and helpful messages for any errors it encounters during the removal of the application. Windows will only detect and report a failure to start the uninstall program.

An uninstall program should complete the following steps:

  • Remove all information used by the application from the registry. If decrementing a DLL's usage count results in a usage count of zero, the uninstall program should display a message offering to delete the DLL or save it in case it may be needed later.
  • Remove any shortcuts to the application from the desktop.
  • Remove all program files related to the application. The uninstall program should not remove files that the user created with the application unless the user agrees to delete them. If the user's files are stored in the application's directory tree, the uninstall program should ask the user if the files should be moved to a new directory.
  • Remove empty directories left by the application.


Setting Up the Environment

Your installation program needs to set up the proper environment for your application. The environment consists of application-specific entries in the initialization files, the registry, and the Start menu. Microsoft Installer Technology, can greatly ease the process of setting up the proper environment.


Setting Initialization Files

Windows does not require the AUTOEXEC.BAT and CONFIG.SYS files. Because these files may not be present on the hard disk, you should make sure that your application does not require entries in those files.

Windows does not require you to modify the PATH environment variable. Instead, Windows looks for your .EXE and .DLL files in the application-specific path specified in the registry. Your installation program is responsible for setting the application-specific path when it installs the application.

Windows does not require an application to load device drivers at boot time. This means that your application does not need to specify drivers in the CONFIG.SYS file. Instead, your application can dynamically load the drivers when it starts by using the virtual device loader functions of Windows or the CreateFile and DeviceIoControl functions.

Your installation program should not make entries in the WIN.INI file. It should be adding entries to the registry instead. Microsoft Installer Technology, provides an easy way to make the necessary registry entries. If you have information that you do not want to put in the registry, your installation program should create a private initialization file and place it in the same directory that contains your application's executable files.


Adding Entries to the Registry

Your installation program should add information about your application to the registry. Microsoft Installer Technology, provides an easy way to make the necessary registry entries. In particular, you should always add the following entries.

HKEY_LOCAL_MACHINE\SOFTWARE\CompanyName\ProductName\Version
Stores information pertaining to this particular copy of the application.
HKEY_CURRENT_USER\SOFTWARE
Stores user-specific preferences. This is information that application vendors used to store in the WIN.INI file. For example Microsoft Word might store the fact that a user wants the automatic save feature turned off here.

Your installation program should always add application-specific paths to the registry for your application. If your installation program registers a path, Windows sets the PATH environment to be the registered path when it starts your application. Your program sets the path in the HKEY_LOCAL_MACHINE root under the \SOFTWARE\Microsoft\Windows\CurrentVersion\AppPaths key (using the REGSTR_PATH_APPPATHS macro). Your installation program must create a new key having the same name as your application's executable file. Under this new key, it creates the Path value name and assigns it a path using the same format as expected by the PATH environment variable.

The following example shows application-specific paths for both Windows® Excel, Excel.Exe, and My Wizzy Application.Exe.

HKEY_LOCAL_MACHINE
  SOFTWARE\Microsoft\Windows\CurrentVersion\AppPaths
    Excel.Exe
      Default=D:\Program Files\MS Office\Excel\Excel.Exe
      Path= D:\Program Files\MS Office\Excel\Excel.Exe;D:\Program
          Files\Common Files\MS Office;

    My Wizzy App.Exe
         Default=d:\Program Files\My Wizzy Application\My Wizzy
             Application.Exe
         Path= D:\Program Files\My Wizzy Application;D:\Program Files\My
             Wizzy Application\Application Extensions;

In the preceding example, the Default value specifies the full path to the corresponding executable file. This value is typically used by Windows in the Start Run command. If the user types the name of your application but Windows fails to find it in the current path, Windows uses this value to locate and start your application.

If you use Microsoft Installer Technology, you should not try to keep track of shared DLLs. Microsoft installer technology keeps track of them for you. However, if you don't use Microsoft installer technology, your application must keep track of its use of shared DLLs itself. When installing an application that uses shared DLLs, it should increment the usage counter for the DLL in the registry. When removing an application, it should decrement the usage counter. If the result is zero, the user should be given the option of deleting the DLL. The user should be warned that other applications may actually need the DLL and will not work if it is missing. The following example shows the general format for usage counters in the registry.

\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLs
    C:\Program Files\Common Files\System\vbrun300.DLL=3


Supporting Context Menu Operations

Your installation program can provide support for context menu operations, such as Open, Print, and Print To, by setting appropriate registry entries. The context menu appears when the user clicks mouse button 2 on a document associated with your application. Microsoft Installer Technology, makes adding these operations easy.

Enabling Print in the registry gives the shell instructions about what to execute when the user chooses Print from the context menu. Usually an application will display a dialog box that says " Printing page n of N on LPTX."

Enabling Print To in the registry specifies the default action for "drag print." Print To displays the same dialog box as Print when you drag it to a specific printer. The Print To option is not displayed on the context menu, so it does not bring up anything (that is, it cannot be chosen).

The following example shows how to set commands for the context menu for files having the .WRI filename extension.

HKEY_CLASSES_ROOT\.wri = wrifile
HKEY_CLASSES_ROOT\wrifile = Write Document
HKEY_CLASSES_ROOT\wrifile\DefaultIcon =
    C:\Progra~1\Access~1\WORDPAD.EXE,2
HKEY_CLASSES_ROOT\wrifile\shell\open\command = WORDPAD.EXE %1
HKEY_CLASSES_ROOT\wrifile\shell\print\command =
    C:\Progra~1\Access~1\WORDPAD.EXE /p "%1"
HKEY_CLASSES_ROOT\wrifile\shell\printto\command =
    C:\Progra~1\Access~1\WORDPAD.EXE /pt "%1" "%2" "%3" "%4"

In the preceding commands, the %1 parameter is the filename, %2 is the printer name, %3 is the driver name, and %4 is the port name. In Windows 95, you can ignore the %3 and %4 parameters (the printer name is unique in Windows 95).


Adding the Application to the Start Button

Your installation program can still create a "Program Group" in the Programs folder by using dynamic data exchange (DDE) as used in Windows version 3.1, but this is no longer the preferred method. Instead, your installation program should add an icon for your primary application to the Start menu. The program can, optionally, prompt the user to choose which program icons to place in the menu. However, icons should not be added for every application in your package, and an extensive hierarchy of programs and folders should not be created on the Start menu.

Microsoft Installer Technology, provides a simple method for populating the Start menu.

To add an icon to the Start menu, your installation program should create a link to your application's executable file by using the IShellLink interface. To determine which directory should contain the link, call the SHGetSpecialFolderLocation function with the CSIDL_PROGRAMS value.


Using Filename Extensions

Filename extensions should always describe a file type. Your installation program should not rename old or backup files by giving them filename extensions like .001, .BAK, or .XX1. If the file type does not change, the program should give the file a new name. For example, it can use long filenames to change the old version of a filename, such as SAMPLE.DLL being changed to Copyof SAMPLE.DLL.

The following table lists filename extensions currently used in Windows. You should not use these filename extensions, unless your file fits the given type description.

Extension | Type description
386 | Windows virtual device driver
3GR | Screen grabber for Microsoft® MS-DOS® – based applications
GR3 | Windows version 3.0 screen grabber
ACM | Audio Compression Manager driver
ADF | Administration configuration files
ANI | Animated mouse cursor
AVI | Video clip
AWD | Fax viewer document
AWP | Fax key viewer
AWS | Fax signature viewer
BAK | Backed-up file
BAT | MS-DOS batch file
BFC | Briefcase
BIN | Binary data file
BMP | Picture (Windows bitmap)
CAB | Windows setup file
CAL | Windows Calendar file
CDA | CD audio track
CFG | Configuration file
CNT | Help contents
COM | MS-DOS –based program
CPD | Fax cover page
CPE | Fax cover page
CPI | International code page
CPL | Control Panel application
CRD | Windows Cardfile document
CSV | Command-separated data file
CUR | Cursor (pointer)
DAT | System data file
DCX | Fax viewer document
DLL | Application extension (dynamic-link library)
DOC | WordPad document
DOS | MS-DOS – based file (also extension for NDIS2 net card and protocol drivers)
DRV | Device driver
EXE | Application
FND | Saved search results
FON | Font file
FOT | Shortcut to font
GR3 | Windows version 3.0 screen grabber
GRP | Program group file
HLP | Help file
HT | HyperTerminal file
ICM | Image color matching (ICM) profile
ICO | Icon
IDF | MIDI instrument definition
INF | Setup information
INI | Configuration settings
KBD | Keyboard layout
LGO | Windows logo driver
LIB | Static-link library
LNK | Shortcut
LOG | Log file
MCI | MCI command set
MDB | File viewer extension
MID | MIDI sequence
MIF | MIDI instrument file
MMF | Microsoft Mail message file
MMM | Animation
MPD | Mini-port driver
MSG | Microsoft Exchange mail document
MSN | The Microsoft Network home base
MSP | Windows Paintbrush picture
NLS | Natural language services driver
PAB | Microsoft Exchange personal address book
PCX | Picture (PCX format)
PDR | Port driver
PF | ICM profile
PIF | Shortcut to MS-DOS – based application
PPD | PostScript® printer description file
PRT | Printer formatted file (result of Print to File option)
PST | Microsoft Exchange personal information store
PWL | Password list
QIC | Backup set for Microsoft Backup
REC | Windows Recorder file
REG | Application registration file
RLE | Picture (RLE format)
RMI | MIDI sequence
RTF | Document (rich text format)
SCR | Screen saver
SET | File set for Microsoft Backup
SHB | Shortcut into a document
SHS | Scrap
SPD | PostScript printer description file
SWP | Virtual memory storage
SYS | System file
TIF | Picture (TIFF format)
TMP | Temporary file
TRN | Translation file
TSP | Windows telephony service provider
TTF | TrueType font
TXT | Text document
VBX | Visual Basic control file
VER | Version description file
VXD | Virtual device driver
WAV | Sound wave
WPC | WordPad file converter
WRI | Windows Write document
XAB | Microsoft Mail address book

You should also investigate filename extensions commonly used by popular applications so that you can avoid creating a new extension that might conflict with them, unless you intend to replace or supersede the functionality of those applications.


Register Document Types

Your installation program should register every file type used that is not provided by the system:

  • For the files of interest to the user, such as document types, the installation program should register both an icon and a description. It should provide good OLE/shell verbs and also add a "ShellNew" entry so your document type shows up in the "New" menu. This menu is available when the user clicks mouse button 2 on any container or chooses the File menu in a folder window.
  • For files that the user would have a good reason to double-click, the installation program should provide the file with a good icon and description and also a registered "open" action so that the user can double-click it.
  • For files that are less interesting to the user, such as .INI or configuration files, the installation program should provide the file with a good icon and description. The best way to do this is to consistently use predefined filename extensions, such as .INI, .SYS, and .TXT.
  • For files of little interest to the user, the installation program should minimally register a file type so that there is a decent description in "Details" view (and possibly an icon). If the program does not register the type, the file is identified by whatever the filename extension may be. Registering the type ensures that the file is identified by the description and related icon.


Network Issues

Most corporate customers would like to run their applications from a network server. To support running from a server, you need to provide your installation application in both a server and client package. The server package consists of executable files, DLLs, data files, and any files that must be shared across the network. The client package consists of the portions of the application that are user-specific, including registry settings, details about the user's configuration, and information about how to locate the server package. Microsoft Installer Technology, provides a powerful way to run applications or portions of applications from the server.

Generally, you should have two installation programs or modes for installing the packages: an administrative installation program that an administrator runs for preparing the server and a client installation program that runs on each client machine and sets up the connection to the server. The client installation program should also have a batch or silent installation option so that an administrator can deploy your application with automatic software distribution tools. Ideally, the client installation functions are built into the application so that it configures itself when it starts (perhaps by reading options set by the administrative installation program).

Corporate customers typically run Windows from a shared copy on a server. The following directories are stored on the server; your application and client installation program may or may not have write access to these directories.

\Windows
    \Command
    \Inf
    \Fonts
    \Help
    \Hyperterm
    \Pif
    \System
        \Color
        \Iosubsys
        \Viewers
        \VMM32

You should use the GetSystemDirectory function to find the SYSTEM subdirectory. To find the WINDOWS directory, look in the following registry location.

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup
    SharedDir=

Your application should store files that cannot be shared (machine-specific files) in a "machine" directory with write access. The machine directory contains files and settings that are specific to a particular machine. If one user changes settings, anyone else who uses that computer gets those settings. If the machine has user profiles turned on, Windows copies the user-specific settings into and out of the machine directory when the user logs on and off. That way, if a user changes a machine setting (that is, a hardware setting), every user is affected, but if the user changes a user-specific setting, the change affects only that user.

The machine directory should not contain any executable files. You can find the machine directory by calling the GetWindowsDirectory function. The following files and directories are stored in the machine directory.

WIN.COM
WININIT.EXE
*.INI
*.GRP 		\Spool
\Desktop
\Startmen
\Nethood

Your application and installation program should fully support Universal Naming Convention (UNC) paths. If an application is being installed on a network path, the installation program should store a UNC path in any shortcuts it makes for the Start menu. Your installation program can use the Windows Network (WNet) functions to determine if a path is a network path.

You should consider what configuration settings an administrator might want to set for a user and what restrictions an administrator might want to place on a user (for example, not letting a user access a configuration menu). You should put these settings and restrictions in a System Policy template (.ADM) file.


CD-ROM Considerations

Autorun is a feature that is supported on CD-ROM drives. When the user loads a compact disc (CD) into the drive, the system automatically runs a file on the CD. The file to run must be specified in an AUTORUN.INF file located in the CD's root directory. The following example shows a typical entry in an AUTORUN.INF file.

[AutoRun]
OPEN=myprog.exe

The autorun feature can be disabled by the device manager or by an entry in the SYSTEM.INI file. Your application must not rely on the autorun feature being available. Also, the autorun feature should not be used to automatically install your application on a user's hard disk without the user being asked first.

If you provide your application on a CD, your installation program should give the user the choice of running the application from the CD or installing it on the hard disk. You should keep the following points in mind when using the autorun feature:

  • Even if the user chooses to run your application from the CD, your program will need to copy some files to the hard disk (for example, writable files and files containing the user's preferences).
  • If you include a shortcut on the desktop, your application should display a message when the user selects the shortcut and the CD is not loaded.


Checklist for Planning an Installation Program

You should keep the following points in mind when you plan an installation program for your application:

  • Use Microsoft Installer Technology.
  • Do not assume that floppies are on Drive A.
  • Use a graphical user interface.
  • Always supply defaults.
  • Name your installation program SETUP.EXE.
  • Tell the user how much space the installation will take and use a progress indicator.
  • Make sure to create all directories in the user selected path.
  • Store private initialization (.INI) files in the application directory if the application is running locally or in the directory returned by the GetWindowsDirectory function if the application is shared.
  • Provide an uninstall option.


Guidelines for Error Messages and Other Event Messages

The guidelines presented here are intended to help developers write clearer and more useful error messages.

In particular, these guidelines have been designed to address three common problems:

  • Users often misunderstand popup errors.
  • Administrators cannot easily understand NT Event Log messages.
  • Product support staffs receive many calls as a result of confusing error messages.

Contents

  • Basic Guidelines
  • Make Your Messages Searchable
  • Style Considerations
  • Message Length
  • Dialog and Popup Message Guidelines
  • Use Windows NT Event Logging
  • Bad Words, Good Words, and Word Rules


Basic Guidelines

  • Do not anthropomorphize. Do not imply that programs or hardware can think or feel. For example, avoid a message such as the following:
    [node name] node does not speak any of our protocols

    Instead, write a message such as:

    Node [node name] cannot use Windows NT protocols
  • Avoid the word "Bad." Try to find a more descriptive term to tell the user what is wrong. For example, avoid, messages such as the following:
    bad link          // Avoid!
bad size          // Avoid!
bad argument      // Avoid!
bad address       // Avoid!
bad CRC           // Avoid!
  • Use full sentences. For example, use "Binding is too long" instead of "Binding too long."
  • Place a searchable word at the start of each message. Avoid starting a message with an article. (the, a, or an). Never put a placeholder variable, such as %1 or %2, at the beginning of a message, since this makes it very difficult for a user to look up the message in our Help File. Instead, write the message so that a searchable word is at the beginning and the placeholder is embedded in the message. For example:
    Log file %1 is full.
   NOT:  %1 log file is full.

Listen failed in %1.
   NOT:  %1: Listen failed.

Computer name %1 is a domain controller of domain %2.
   NOT:  %1 is a domain controller of domain %2.


Make Your Messages Searchable

Place words that are both searchable and relevant to the central meaning at the beginning of the message string. For example:

Recycle Bin cannot store some of the items you are about to delete.
   NOT:  Some of the items you are about to delete cannot be
         stored in the Recycle Bin.

Endpoint was not found.
   NOT:  No endpoint was found.

Move you specified requires moving text cards.
   NOT:  That move requires moving text cards.

Log file filename is full.
   Not:  The filename log file is full.

Computer name as entered is not valid.
   NOT:  The computer name you typed is invalid.
   NOT:  Invalid computer name.

Chat application cannot start.
   NOT:  The application cannot start" in Chat component.


Style Considerations

Users almost always prefer simple sentences that use simple present or past tense and active voice. For example:

Registry Editor cannot create the subkey.
   NOT:  ...could not create...

Setup cannot start Program Manager.
   NOT:  Setup was unable to activate Program Manager.

Floppy disk sector ID field does not match floppy disk controller track address.
   NOT:  Mismatch between the floppy disk sector ID field and the
         floppy disk controller track address.

CHKDSK encountered an error during...
   NOT:  An error was encountered during...

Cannot find %1.
   NOT:  Could not find...

Modem does not respond.
   NOT:  Modem not responding.

However, using active voice and a simple constructions is less important than making your message searchable. Use passive voice and more complex constructions if you need to in order to place search-relevant words at the beginning of the message. For example:

Log file size cannot be adjusted.
   NOT:  Cannot adjust the size of the log file.
   NOT:  Was unable to adjust the size of the log file.

Printing of %1 cannot resume.
   NOT:  Cannot resume printing %1.
   NOT:  Could not resume printing %1.


Message Length

Wordiness or verbosity of messages should depend on the component.

  • Strings from components that have the potential to destroy an installation or cause the system to crash should include more explanation and user guidance. For example, Setup and STOP messages can contain more text in the string itself.
  • Strings from components that will be displayed often to less technical users (as opposed to administrators or tech support) can also be longer. For example, Print Manager and IIS messages can be more verbose.
  • Strings that will display mostly to technical users should be shorter. Explanation and user action fields in the Messages Help file can go into more detail for these users. For example, WINS and TCP/IP messages should be brief and to the point.


Dialog and Popup Message Guidelines

This type of message is often very confusing to users. A dialog box has appeared on the screen and will not go away until they click the "OK" or "Cancel" button.

Users often feel they have "broken" something on the computer and are not sure what to do next.

When writing this type of message, consider the following:

  • Does the message give the user a clear, non-technical explanation of the problem?
  • Does the message include steps or a clear explanation of what to do to prevent the problem from occurring again?
  • If a long explanation is needed, point the user to a Help file and index item to search for more information.
  • If it is a critical problem, be sure to leverage the Event Log and write out the error.


Use Windows NT Event Logging

Event logging in Microsoft Windows NT provides a standard, centralized way for applications and the operating system to record important software and hardware events. It also provides a standard user interface for viewing the logs and a programming interface for examining the logs. Event logging provides a means to merge events from various sources into a single informative story.

The event log functions allow three kinds of event reports to be generated:

  • Information: You have something to report that does not require any interaction from the user or administrator, but could help in any future troubleshooting.
  • Warning: Your component had a problem but was able to recover. These messages are invaluable in troubleshooting.
  • Error: Your component had a problem and most likely was unable to recover. This type of error usually needs user intervention to correct the problem.

Remember the audience - administrators and users who are trying to troubleshoot the problem.

A message should contain:

  • All the information needed to interpret what caused the problem.
  • What to do to correct the problem.

This may seem like basic advice, but many error messages are cryptic. For example, avoid a message like the following:

A driver packet received from the I/O subsystem was invalid.
The data is the packet.

What this message means is that the driver in question is functioning properly, but is logging incorrectly formatted packets in the event log. To correct the problem, a Unicode version of the driver is needed.

When you start to write your message, you should consider the following:

  • Is the information useful to the user, administrator, and product support staff?
  • If it is debug information, do not include it in the retail product.
  • Do not use tabs or commas in the message text. Event log files can be saved as comma or tab separated text files. Many organizations import these files into databases and the extra formatting characters require manual manipulation.


Bad Words, Good Words, and Word Rules

Do Not Use the Following Bad Words

abort
Instead, use end communications or network connections, quit programs, and stop hardware operations.
boot, reboot
Instead, use start or restart.
Contractions such as can't and don't
Instead, use cannot and do not.
enter (verb)
For a selection that a user can either type or click.
log in, login, log onto, log off of, logout, sign off, or sign on
Instead, use log on to, log off (verb), or logon (adjective).
please
Brevity is valued more than empty courtesy.
  • NT

    Instead, use Windows NT.

Do Use the Following Good Words

click
Do not use click on.
corrupted (adj.)
Do not use corrupt.
dialog box
Do not use dialog alone, and never use dialogue.
disk
Do not use diskette.
filename
Do not use file name.
hard disk, or hard disk drive
Do not use hard drive, internal drive, fixed drive, or hard disk system.
K as the abbreviation for kilobyte.
It should follow the number with no space. For example, 40K. Do not use KB, K byte, or Kbyte.
MB as the abbreviation for megabyte.
It should follow the number with a space between 40 MB. Do not use M, meg, or Mbyte.
might
Do not use may.
MS-DOS
Do not use just DOS.
multiple-boot (adj.)
Do not use dual-boot.
path
Do not use pathname.

Keep in Mind the Following Word Rules

permissions vs. rights
A permission is a rule associated with an object, such as a file, directory, or printer, that is shared on a network. Permissions can be assigned to groups, global groups, or to an individual user. By contrast, rights apply to the system as a whole.

Do not use privileges or permission records.

its
"Its" is a possessive pronoun; it's is the contraction for "it is."
open
You open a window, file, document, or folder, but not a command, menu, icon, option, or other element that doesn't produce a working file.
prefixes
Do not hyphenate words with prefixes. For example, use nonzero (not non-zero), nonrecoverable (not non-recoverable), preempt (not pre-empt), subsection (not sub-section), unreadable (not un-readable).
press
You press a key that initiates an action or moves the user's position. (See also enter)
quit
You quit a program (not close, end, exit, leave, stop, or terminate).
  • Registry

    Registry always has a capital "R".

start
You start a program (not boot, initiate, initialize, issue, or turn on).
stop
You stop a hardware program. For example, you "stop a print job."
type
You type information that will appear on the screen. Exception: You enter a filename that can be either typed or selected from a list.


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.