Win 32 Prog
Win 32 Prog
Page 1 of 119
Introduction
Programming Techniques contains topics that are of interest to programmers writing Win32-based applications. It is a supplement to the Win32 Programmers Reference and the documentation included with your development tools. It is not a comprehensive guide. Programming techniques contains the following sections: Win32 Application Programming Interface Writing Great Win32-based Applications The Generic Win32-based Application Overview of the Build Process Installing Applications WINDOWS.H and STRICT Type Checking Porting Code From 16-bit Windows to 32-bit Windows Handling Messages with Portable Macros Generic Thunks
Introduction
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
Page 2 of 119
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.
Introduction
Page 3 of 119
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 applications 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 shells 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 shells 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 applications 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.
Introduction
Page 4 of 119
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 the New Technology File System (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.
Introduction
Page 5 of 119
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. Windows NT Windows 95 Windows 3.1 with Win32s Feature Yes No No 32-bit Coordinate System Yes Yes Yes 32-bit Flat Memory model Yes Yes Yes 3-D look Asynchronous file I/O Yes No No Yes Yes No Asynchronous input model COMM Yes Yes Via Universal Thunk Common Controls Property sheet Yes Yes Yes tabs Drag list boxes Yes Yes Yes Toolbar Yes Yes Yes Status bar Yes Yes Yes Column Yes Yes Yes heading Spin buttons Yes Yes Yes
Introduction
Slider Scrolling button indicator Rich Edit Control Progress indicator Tree View List View Common Dialogs Console Support Context menu on mouse button 2 Enhanced metafiles Event logging File mapping File merge/reconciliation File Viewers Image Color Matching (ICM) Long Filenames (LFN) Multimedia API Multiprocessor Machines Named pipes National Language Support (NLS) Network DDE Non-Intel machines Paths/Beziers Pen Plug and Play event aware Preemptive multitasking Print spooler Remote Access Services (RAS) Remote Procedure Calls (RPC) Security Security (C2 certifiable) Separate address space Service control manager Simple MAPI Structured exception handling (SEH) TAPI Threads Unicode Universal Naming Convention (UNC) User & GDI system resources Windows 4.0 help Windows Network (WNet) Windows Sockets World transforms Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
Page 6 of 119
Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Except code page No Yes Yes Yes Yes Yes No Yes No No Yes Yes Yes Yes Yes No Yes Yes Not used Not yet Yes No Yes Yes Won't appear Yes Yes Windows 3.1 level Yes No No Yes Client-side Client-side Yes Yes Yes Yes Via Thunk No Yes No No Yes Limited No No Yes No Won't get events Yes Won't get events Yes Yes No Yes Except forms No Yes Yes No Yes Yes Via thunk Yes No No Yes No No Yes Yes No Yes No No Yes Yes Via Universal Thunk Yes Yes Yes Yes Yes No Yes Yes No Yes No No Yes Yes Yes Virtually Unlimited Expanded Win3.1 limits Yes Yes Context menu help won't appear Yes Yes Via Universal Thunk Yes Yes Yes Yes Scaling Only No
Introduction
Page 7 of 119
File Information
Throughout the shell, files appear as icons. When you click on a files icon using mouse button 2, the system displays a context menu containing commands that perform actions on the file. One of the commands, Properties, displays a special dialog box called a property sheet that contains information about the file. By viewing a files property sheet, the user can find out information about a file without having to open it. By default, a files property sheet contains general information about the file, including its name, size, location,
Introduction
Page 8 of 119
creation date, attributes, and so on. The following illustration shows the default property sheet for a typical file.
If your application creates files with additional properties that the user may be interested in, you should add more pages to the property sheets for the files. One way to add property sheet pages to an application using OLE structured storage is to store documents in compound files (also called docfiles) and use the Document Summary Information Property Set to store summary information and editing statistics for the documents. When the user activates the property sheet for the document, the shell automatically gathers the summary information and editing statistics from the document and adds them to the property sheet as two additional pages. The following illustration shows a property sheet with Summary and Statistics pages added based on data gathered from the document.
Introduction
Page 9 of 119
For more information about saving document information using the OLE Document Summary Information Property Set, see the OLE Programmers Reference. Another way to add pages to file property sheets is to write a shell extension (OLE InProcServer32) that includes a property sheet handler. Whenever the user activates the property sheet for a file, the system checks the registry to see if any property sheet handlers are registered for the file type. If there are some registered, the system calls the handlers before displaying the property sheet. The handlers can add any number of pages to the property sheet before it is displayed. For more information about shell extensions and property sheet handlers, see Shell Extensions.
Long Filenames
Windows allows users and applications to create and use long filenames for their files and directories. A long filename is a name for a file or directory that is longer than the standard MS-DOS filename format (8 character base, 3 character extension). An application should support long filenames and display them correctly. You can use the SHGetFileInfo function in your application to retrieve the long filename for a file as well as the files icon, type name, attributes, and so on. If you include the File Open and Save As common dialog boxes in your application, you can use the OFN_LONGNAMES value to direct the dialog boxes to display and return long filenames. Before an application displays a long filename, it should hide the filename extension. For example, the application should display a filename like My letter to Mom instead of My letter to Mom.Doc. An application can hide filename extensions on a file-specific basis by using the SHGetFileInfo function. The following illustration shows a folder containing documents with long filenames.
Introduction
Page 10 of 119
If an application is used to view or edit a document or data file, the title bar of the window that contains the file should display the long filename for the file. If the title bar also includes the applications name, it should appear to the right of the filename. Displaying the filename first places the emphasis on the document or data rather than on the application. For more information about long filenames, see Long Filenames. You should also support Universal Naming Convention (UNC) path names for files in your application. Using UNC names enables users to browse documents on the network directly and to open an applications files on remote machines without needing to know the location of the file on the network or having to make an explicit network connection.
Context Menus
A context menu is a pop-up menu containing a set of commands that are specific to a particular object. Windows provides a context menu for all objects that appear in the shell, including files, folders, printers, and so on. A context menu appears when the user clicks an object using mouse button 2. Because context menus are displayed at the pointers current location, they eliminate the need for the user to move the pointer to the menu bar or toolbar. They also help eliminate screen clutter. You should provide context menus for all objects in an application and should display the context menu whenever the user clicks an object using mouse button 2. Each context menu should include a Properties command that displays a property sheet for the object. In addition to displaying a context menu for objects, an application should also display a context menu when the user clicks the small icon in the title bar using mouse button 2. The commands in the context menu should operate on the object that is open in the window, not on the window itself. To see an example of a context menu associated with a title bar icon, click the title bar icon of a folder window in the shell using mouse button 2. For more information about context menus, see Shell Extensions.
Icons
If your application supports OLE, you should make sure that the icons for your embedded and linked objects are consistent with the shell. For example, when the user drags an icon from the shell into your container, the icon and its name should stay the same. You should support interactions with embedded icons the same way that the shell does. For example, when the user selects the icon for an embedded object, you should dither the icon with the system highlight color rather than enclosing it in a rectangle that has resizing handles.
Introduction
Page 11 of 119
Shortcuts
A shortcut (also called a shell link) is a data object that contains information used to access another object in the system, such as a file, folder, disk drive, or printer. A shortcut has an icon associated with it; the user accesses the object associated with a shortcut by double-clicking the shortcuts icon. The associated object can be stored anywhere in the system. Typically, the user creates shortcuts to gain quick access to objects stored in subfolders on the same machine or to shared folders on other machines. For example, the user can create a shortcut to a Microsoft Word document located in a subfolder and can place the shortcut icon on the desktop. The user can later start Word and open the document simply by double-clicking the shortcut icon. If the document is later moved or renamed, the system takes steps to update the shortcut the next time the user selects it. An application should support shortcuts. For example, a word processing application might allow the user to drag and drop a shortcut icon into a document file. An application should also correctly dereference shortcuts. For example, if the user specifies the filename of a shortcut when using an applications Open command on the File menu, the application should open the object associated with the shortcut, not the shortcut file itself. For more information about shortcuts, see Shell Links.
Common Controls
The common controls are a set of control windows that are supported by the common control library, which is a DLL called COMCTRL32.DLL. Like other control windows, a common control is a child window that an application
Introduction
Page 12 of 119
uses in conjunction with another window to perform input and output (I/O) tasks. The common control DLL includes a programming interface that you use to create and manipulate the controls and dialog boxes and to receive user input from them. This section describes some of the controls provided by the common control DLL. Header Control A header control provides headings for columns of text or numbers. It can be divided into many parts, and each part can have its own heading text. The user can adjust the width of the columns by dragging the dividers that separate the parts.
Property Sheet A property sheet displays the properties of an object, such as a document file or a cell in a spreadsheet. Related properties can be grouped together and placed on separate, overlapping pages within the property sheet. Each page has a tab that the user can select to bring the page to the foreground. An application can create a special type of property sheet called a wizard control. The control displays a sequence of pages that guide the user through the steps of an operation, such as setting up a device or creating a birthday card.
Introduction
Page 13 of 119
Up-Down Control An up-down control consists of a pair of arrow buttons that the user can click to increment or decrement a value, such as a scroll position or a number displayed in an accompanying edit control.
Tree View Control A tree view control displays a hierarchical list of items, such as the headings in a document, the entries in an index, or the files and directories on a disk. By clicking an item, the user can expand or collapse the associated list of subordinate items. The user can select items, edit item labels, and drag items from one location to another.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Status Window
Page 14 of 119
A status window displays information that may be useful to the user. It is typically positioned along the bottom of a window and can be divided into parts to display different types of information simultaneously.
Toolbar A toolbar contains buttons that carry out commands when the user selects them. Typically, the buttons correspond to menu items, providing a quicker, more direct way for the user to access an applications commands.
Progress Bar A progress bar indicates the progress of a lengthy operation. It consists of a rectangle that is gradually filled with color, from left to right, as the operation progresses.
List View Control A list view control displays a collection of related items, each consisting of an icon and a descriptive label. The items can be arranged and displayed in different ways to suit the users preferences. The user can select items, edit item labels, and drag items from one location to another.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Trackbar
Page 15 of 119
A trackbar allows the user to select a value from a range of consecutive values. To select a value, the user drags the trackbars slider to the desired position.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 16 of 119
Palette
If your application supports 256 colors, you should use the Windows halftone palette, as the shell does. It helps system performance, because the system does not need to load a new palette every time the execution focus switches between the shell and your application.
Windows Help
Windows Help includes many features that you can use to provide help information that is task- or object-specific as well as readily accessible and unobtrusive. You should consider including the following features in your applications help file: Provide context-sensitive help for your dialog boxes and documents. The user can access context-sensitive help by clicking mouse button 2 (if there is no context menu available) or pressing the F1 key to display help information for a specific object or element in the application. The following illustration shows context-sensitive help for a control in a dialog box.
Use secondary windows for procedural help. A secondary window does not have menus, and it remains open until it is explicitly closed. Embed shortcut buttons in your help text. A shortcut button allows the user to start an application from within a help file. Use sizable topic windows to make help text easier to read. Consider using the built-in support for training cards.
Multiple Views
You should not let the user open multiple views of the same document. Multiple views confuse the user and conflict with the datacentric design of Windows.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 17 of 119
When the user attempts to open a document file associated with an application, typically by double-clicking the document files icon, the application should determine if the document file is already open. If it is, the application should check whether the current user has attempted to open the file. The application should do more than just compare user names because the user may be logged onto more than one computer. If the current user already has the document file open, the application should immediately restore the window containing the open document file. If the current user has not attempted to open the document file (meaning that someone else on the network has), the application should prompt the user with the following message. This document has already been opened by <name>. Would you like to make a copy?
If the user does not want to make a copy, the application should exit; otherwise, it should make a copy. You should also handle the case where the user double-clicks an applications icon when the application is already running. If the applications default action is to open a blank document when the user double-clicks the icon, the application should present the user with a list of currently opened documents. Opening a new document, however, should be the default action.
Pen Input
Windows 95 only An application should support pen input so that it is easy to use on pen-based platforms, such as notebook computers and desktop tablets. The following list briefly describes what you need to do to support pen input: Use functions from the Windows pen application programming interface (API) to activate the pen in your application. If you activate the pen, the user can enter text using handwriting recognition and edit documents using gestures. Incorporate ink-edit controls into your application. Ink-edit controls allow the user to enter scribbled notes, drawings, and signatures. Add other natural pen-oriented features and gestures to your application.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
runs exclusively in full screen mode is one that cannot run in a window or be minimized. Utilities (for example, virus scanners and disk management programs). Development tools (for example, compilers and linkers).
Page 18 of 119
To qualify for the Windows 95 Logo, an application must meet the appropriate requirements in the following list. The first five requirements apply to all types of applications. 1. An application must use the Win32 application programming interface (API) and must be compiled using a 32bit compiler that generates an executable file of the Portable Executable (PE) format. If your application is not represented in the PE format (for example, it uses interpreted code), the run-time engine must be an executable file in the PE format. For example, if you develop an application in Microsoft Access, your application is an .MDB file, not an .EXE, but ACCESS.EXE would need to be a PE format executable file. 2. An application must support the new shell and user interface. At a minimum, an application must meet the following requirements: Register both 16- by 16-pixel and 32- by 32-pixel icons for each file type and the application. Follow the user interface guidelines described in The Windows Interface Guidelines for Software Design. An application should also use the system-defined dialog boxes and controls. Use the system metrics for setting the size of elements within the application. Use the system-defined colors. Use the right mouse button for context menus (and not for any other purpose). Follow the application installation guidelines to make the application properly visible in the shell. At a minimum, this means that you should use the registry, you should not add information to the win.ini or system.ini file, and you should provide complete uninstall capabilities with your application. In addition, the installation process must be automated. For more information about installation guidelines, see Installing Applications. For detailed guidelines about supporting the shell and user interface, see The Windows Interface Guidelines for Software Design. 3. An application must be tested on the latest version of Microsoft Windows NT. If it uses features available only in one platform, the application must handle this gracefully when running on the other platofmr. 4. An application must support long filenames and use them to display all document and data filenames in the shell, in title bars, in dialog boxes and controls, and with icons. In addition, an application should hide the extensions of filenames that are displayed within the application itself. 5. An application should process Plug and Play events. For example, it should be aware of slow links and should react to system messages that occur when a new device is attached or removed. The next three requirements apply to file-based applications that do not run in full screen mode. Some games and childrens software run exclusively in full screen mode and need not follow these three requirements. 6. An application must support Universal Naming Conventions (UNC) names for paths. 7. An application must support OLE containers or objects, or both. It must also support the OLE style of drag and drop. An application should also support OLE automation and compound files (with document summary information included).
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 19 of 119
8. An application must support simple mail enabling using the Messaging Application Programming Interface (MAPI) or the Common Messaging Call (CMC) API. That is, it must include Send Mail functionality. The following items are modified requirements for utilities, such as disk optimizers and anti-virus software: 9. Same as number 1, except for components that must use exclusive volume locking functions, soft interrupts, or components that must talk directly to 16-bit drivers. The user interface and other components of these applications must be 32 bits and use the Windows 95 thunking mechanism to access the 16-bit components. 10. Same as number 2. 11. Same as number 3, except for products like disk utilities that implement platform-specific functionality that does not make sense in Windows NT. 12. Same as number 4. 13. Numbers 5 through 8 are recommended, but not required. However, number 6 is required if your product accesses network resources. The following items are modified requirements for compilers and other development tools: 14. In addition to the requirements that follow, if Windows is one of the target platforms of a compiler or development tool, the compiler or tool must be capable of generating applications that can meet all of the Windows 95 Logo requirements. 15. Same as number 1. 16. Same as number 2, except that when icons are registered for each file type and the application, common source filename extensions, such as .C, .CPP, .H, and .HPP, are excluded. 17. Same as number 3. 18. Same as number 4. 19. Same as number 5. 20. Same as number 6. 21. Compilers and development tools must support OLE in the following ways: Support the OLE style of drag and drop (recommended within the tools design environment). Support OLE automation (recommended, but not required). Provide an easy way to create applications with OLE container or object support, or provide this functionality by default. 22. Same as number 8 (recommended, but not required).
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 20 of 119
requirements as outlined below and pass the System Compatibility Test (SCT). The SCT tests are included in the Microsoft Windows 95 Device Driver Kit (DDK), along with instructions for OEM participation. System testing is OEM-administered, and results are sent to Microsoft Compatibility Labs (MCL). A PC system must meet the following requirements: 1. 80386 or compatible processor. (However, 33-megahertz 80486 or better is recommended.) 2. 4 megabytes (MB) random-access memory (RAM). (However, 8 MB is recommended.) 3. Plug and Play basic input/output system (BIOS) version 1.0a or later that reads back all resources. (However, a BIOS that soft-sets all resources is recommended.) 4. Molded-in or permanently printed icon labels on the computer case for built-in ports. Ideally, icons on the cable connectors should match the icons on the computer case. 5. Optional read-only memory (ROM) chips on expansion cards must use the Plug and Play header format documented in the Plug and Play BIOS specification. 6. A Video Graphics Array (VGA) display adapter that uses a packed-pixel frame buffer and provides a resolution of at least 640 by 480 pixels and 8 bits per pixel (bpp) for desktop systems and a 64-shade gray scale for mobile systems. (However, VGA 1024 by 768 pixels and 8 bpp is recommended for desktop systems, and 64 colors is recommended for mobile systems.) 7. One parallel port that supports IEEE-P1284-I mode protocols for compatibility mode and nibble mode. The system must be capable of receiving the parallel devices identifier in nibble mode. (However, ECP P1284-I is recommended.) 8. One integrated or separate serial port, with 1-16550A required for mobile systems. Also recommended are 116550A for desktop systems, an additional PS/2 style port, pen devices with a barrel button, and serial infrared devices meeting the Infrared Data Association (IrDA) specification. 9. Advanced Power Management (APM) version 1.1 is required for mobile systems. (However, it is recommended also for desktop systems.) If the system ships with expansion cards or peripheral devices integrated onto the motherboard, it is recommended that the cards or devices meet the Windows 95 Logo specifications defined in this article and use 32-bit Windows 95 based device drivers. For more information about qualifying a PC for the Windows 95 Logo, see the Hardware Design Guide for Windows 95.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
2. Is dynamically loadable. 3. Is dynamically reconfigurable. 4. Reacts to system messages that occur when a device is attached or removed.
Page 21 of 119
An ideal Windows 95 based Plug and Play driver requires minimal user interaction to select the proper driver. In addition, the settings for the device may need to change based on which user is logged in, whether the machine is docked or not, or both.
Display Adapters
Display adapters must meet the following requirements: 1. Support the VGA graphics standard. 2. Support at least a 640- by 480-pixel, 8 bpp display driver. Desktop systems must be able to display at least 256 colors, and mobile systems must support an 8 bpp driver and map colors into at least a 64 gray scale display so that changes to higher-resolution external monitors can be made without restarting Windows 95. 3. Use a packed-pixel frame buffer with at least 8 bpp. 4. Use a VGA BIOS that, if it exists separately, has its base address fixed at C000h. (However, an alternate address is recommended.) 5. Use a standard VGA with a page frame and I/O address resource that can be static that is, not relocatable. 6. Support the Video Electronics Standards Association (VESA) ergonomic timings. 7. Be capable of being disabled if a conflicting VGA expansion card is added to the system. 8. Provide at least one alternate configuration in case of conflict during initial program load (IPL) boot (non-VGA display resources only). The VGA BIOS must be able to use alternate configuration register addresses. 9. Have the display adapter circuitry come up active when power is turned on or the system is reset. This requirement applies only to an Industry Standard Architecture (ISA) Plug and Play display adapter expansion cards used as a system boot device.
Audio Adapters
Audio adapters must meet the following requirements: 1. Be able to produce 22 kilohertz (kHz), 8-bit, monaural, output-only sound (minimum performance). 2. Support either Sound Blaster or the Microsoft Windows Sound System to use built-in drivers for Windows 95. 3. Use a one-eighth inch miniature phone jack wired for stereo as the output connector. 4. Map the base input and output (I/O) address to configurations compatible with either Sound Blaster or the Microsoft Sound System.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 22 of 119
5. Support at least all interrupt request (IRQ) signals used either by Sound Blaster or the Microsoft Windows Sound System. 6. Support the selection of at least three available Direct Memory Access (DMA) channels, either 8 bit or 16 bit, if DMA is supported. 7. Support disabling in case of resource conflicts with other devices.
Storage Devices
This section lists the requirements for storage devices, including floppy disk controllers, ATA (IDE) adapters, ATA (IDE) peripherals, small computer system interface (SCSI) host adapters, and SCSI devices. Floppy Disk Controllers Floppy disk controllers must meet the following requirements: 1. Use at least three static I/O addresses: 3F2h, 3F4h, and 3F5h. 2. Support IRQ6. 3. Support at least DMA 2, if DMA is used. In addition, the controller should be capable of selecting at least two other available DMA channels, either 8 bit or 16 bit. 4. Be capable of being independently disabled. ATA (IDE) Adapters ATA (IDE) adapters must meet the following requirements: 1. Use the first device attached to the adapter as the boot device. 2. Use the standard I/O addresses: 1F0h through 1F7h and 3F6h. 3. Support at least IRQ14. 4. Be capable of being disabled if an ATA (IDE) expansion card is added to the system. In addition, if a single adapter card contains a floppy disk drive controller, the adapter must be able to independently disable the floppy drive controller if a conflict occurs. ATA (IDE) Peripherals ATA (IDE) peripherals must meet the following requirements: 1. Support the ATA Packet Interface (ATAPI) protocol for CD-ROMs defined in SFF-8020 version 1.2. 2. Comply with the requirements specified in the ATA 2 specification. 3. Set the signature after an ATA Read or ATA Identify Command is received. 4. Implement the SEEK command and set the DSC bit when the ATAPI seek is complete, but not change the drive select bit.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 23 of 119
5. Return the CANNOT READ MEDIUM - INCOMPATIBLE FORMAT additional sense code qualifier when a READ is received on an audio track. 6. Support CD-DA. 7. Support the READ_CD command sector types mode 2 form 1, mode 2 form 2, mode 1 form 1, and mode 1 form 2. 8. Support the Test_Unit_Ready command. SCSI Host Adapters SCSI host adapters must meet the following requirements: 1. Meet the standards described in the current version of the Plug and Play SCSI specification. 2. Support the SCSI Configured Auto-Magically (SCAM) Level 1 protocol for automatic SCSI identifier assignment. 3. Use the 50-pin, high-density shielded device connector defined in the SCSI-2 standard (external SCSI peripheral subsystems only). 4. Select at least three available DMA channels, either 8 bit or 16 bit, if DMA is supported. 5. Support disabling in case of resource conflicts with other devices. 6. Support automatic switchable termination for Plug and Play operation of internal, external, or mixed SCSI configurations. SCSI Devices SCSI devices must meet the following requirements: 1. Meet the standards described in the current version of the Plug and Play SCSI specification. 2. Support the SCSI Configured Auto-Magically (SCAM) Level 1 protocol for automatic SCSI identifier assignment. 3. Use the 50-pin, high-density shielded device connector defined in the SCSI-2 standard (external SCSI peripheral subsystems only). 4. Use the drivers and receivers that meet the specifications defined in the single-ended alternative of the SPI. 5. Use cables that conform to the cable requirements defined in clause 6 of the SPI specification. 6. Ensure that external SCSI peripherals contain two connectors for the SCSI cable: a SCSI in connector and a SCSI out connector. The last peripheral in the chain uses a terminator on the SCSI out connector. 7. Support the attachment of a permanent terminator to the end of the cable for internal SCSI peripherals. 8. Ensure that internal SCSI peripherals do not terminate the SCSI bus. 9. Ensure that terminations conform to the terminator requirements in the SPI specification over the terminator power (TERMPWR) voltage range of 4.0 to 5.25 VDC.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
10. Power terminators from the TERMPWR line on the SCSI bus. 11. Provide overcurrent protection for the TERMPWR line or lines. 12. Ensure that only terminators draw power from TERMPWR. 13. Implement the SCSI Bus Parity signal defined in the SCSI-2 specifications.
Page 24 of 119
Modems
Modems must meet the following requirements: 1. Support at least 9600 bits per second (bps) V.32 with V42/V42bis protocol for data modems. 2. Support the TIA-602 (Hayes-compatible) AT command set, with extensions for flow control, V42/V42bis. 3. Support fax capabilities of at least 9600 bps V.29 with class 1 (TIA-578A). 4. Support Plug and Play device identification, using the appropriate Plug and Play specification (for example, ISA bus, COM port, PCMCIA slot, or LPT port). 5. Support the 16550A compatible universal asynchronous receiver-transmitter (UART) interface.
Network Adapters
Network adapters must meet the following requirements: 1. Support the network driver interface specification (NDIS) 3.1 network device driver, which allows dynamic starting and stopping of the network card. 2. Provide a means of automatically enabling the adapter as a boot device or enabling the adapter as a
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 25 of 119
nonbootable device, if the network adapter is designed with Remote Initial Program Load (RIPL) capability. 3. Do not hook Interrupt 18 and Interrupt 19 on ISA bus systems. This is a requirement for an ISA Plug and Play card. 4. Support at least seven IRQ signals and enable/disable. 5. Select at least three available DMA channels, either 8 bit or 16 bit, if DMA is supported. 6. Support disabling in case of resource conflicts with other devices.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 26 of 119
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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
The GENERIC application uses the following message loop: while( GetMessage( &msg, NULL, 0, 0 ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); }
Page 27 of 119
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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 28 of 119
The WM_PAINT message indicates that you should redraw whats in all or part of your applications window. Use the BeginPaint function to get a handle to a device context, then use the device context for drawing within the applications 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;
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 29 of 119
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 userinput 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 * * *
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
* Functions: * * WinMain - Application entry point * * MainWndProc - main window procedure * * AboutDlgProc - dialog procedure for About dialog * * * * * \********************************************************************/ /********************* #include <windows.h> #include "generic.h" /********************* Prototypes ***********************/ Header Files *********************/
Page 30 of 119
LRESULT WINAPI MainWndProc( HWND, UINT, WPARAM, LPARAM ); LRESULT WINAPI AboutDlgProc( HWND, UINT, WPARAM, LPARAM ); /******************* 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, Global Variables ********************/
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
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 );
Page 31 of 119
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
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. * * * \********************************************************************/
Page 32 of 119
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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
/*************************************************************\ * generic.rc: Resource script for Generic * * * * * \*************************************************************/ #include <windows.h> #include "generic.h" #include "generic.dlg" GenericAppMenu MENU { POPUP "&Help" { MENUITEM "&About", } }
Page 33 of 119
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
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 34 of 119
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 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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 35 of 119
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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 36 of 119
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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
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(...);
Page 37 of 119
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 DCs 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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 38 of 119
you do not do this, you get alignment faults. On some systems, these simply generate traps, and you can fix your program. However, some systems handle your unaligned references with a trap handler. This slows down your application and can be difficult to track down.
Using 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 Building Applications Building DLLs Using the C Run-Time Library
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
The file should be included in your makefile as follows: !include <win32.mak>
Page 39 of 119
It is recommended that you examine the contents of WIN32.MAK, located in the MSTOOLS\INCLUDE subdirectory.
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
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
$(CC) This macro is used to invoke the compiler. It expands to the following: cl $(CFLAGS)
Page 40 of 119
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)
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
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
Page 41 of 119
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
Building Applications
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 entrypoint function (main or WinMain).
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Use one of the following flags if you are using the single-threaded CRT: $(CONLIBS)
Page 42 of 119
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.LI 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. 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. 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 building applications. WIN32.MAK also includes the following macros
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
to simplify linking DLLS: $(IMPLIB) This macro is used to invoke the library manager. It expands to the following flags: lib $(DLLENTRY)
Page 43 of 119
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
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 44 of 119
The CRT libraries are not distributed with the Win32 SDK. Many vendors distribute similar forms of the CRT, but with different names. These name differences can be encapsulated in WIN32.MAK. 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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 45 of 119
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).
Installing Applications
This article describes a standard set of guidelines for installing Win32-based applications.
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 users 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. An installation program (or a companion program) should also be prepared to update or remove an already installed application. You are responsible for designing and implementing the installation program for your application. Windows does not provide a default installation program, but it does provide 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 readonly 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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 46 of 119
easy-to-implement features that will add value to your application and make use of new usability functionality in the shell. Your installation program should always offer setup options. The following options are recommended. Typical Installs the application with all of the most common settings and copies the most commonly used setup files. This should be the default setup option. Compact Copies the fewest number of files needed to operate your application. This option is useful for setup laptops and computers on which disk space is at a premium. Custom Allows the user to determine the details of the installation, such as the directories to receive the files setup 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 Runs setup without user interaction. This should just be a command line option so that your setup 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 users hard disk.
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
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 47 of 119
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 applications 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 applications 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, your installation program should increment the usage counter for the DLL in the registry. For more information about the usage counter, see Adding Entries to the Registry. 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.
Windows NT
To replace DLLs already loaded in memory, use the MoveFileEx function.
Windows 95
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 48 of 119
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 users 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 users 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 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: 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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
HKeyLocalMachine\Software\Microsoft\Windows\CurrentVersion\Fonts
Page 49 of 119
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 users 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 by adding the following entries to the registry. HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\application-name 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. If both the DisplayName and UninstallString values are not complete, 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. Your installation program should use casual names, including spaces, for the application-name and DisplayName value. Casual names help keep the tree comprehensible for users who browse the registry. 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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
An uninstall program should complete the following steps:
Page 50 of 119
Remove all information used by the application from the registry. If decrementing a DLLs 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 users files are stored in the applications 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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 51 of 119
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 an 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 applications 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. Your installation program should keep track of shared DLLs. 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
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
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"
Page 52 of 119
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).
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
BIN BMP CAB CAL CDA CFG CNT COM CPD CPE CPI CPL CRD CSV CUR DAT DCX DLL DOC DOS DRV EXE FND FON FOT GR3 GRP HLP HT ICM ICO IDF INF INI KBD LGO LIB LNK LOG MCI MDB MID MIF MMF MMM MPD MSG MSN Binary data file Picture (Windows bitmap) Windows setup file Windows Calendar file CD audio track Configuration file Help contents MS-DOS based program Fax cover page Fax cover page International code page Control Panel application Windows Cardfile document Command-separated data file Cursor (pointer) System data file Fax viewer document Application extension (dynamic-link library) WordPad document MS-DOS based file (also extension for NDIS2 net card and protocol drivers) Device driver Application Saved search results Font file Shortcut to font Windows version 3.0 screen grabber Program group file Help file HyperTerminal file Image color matching (ICM) profile Icon MIDI instrument definition Setup information Configuration settings Keyboard layout Windows logo driver Static-link library Shortcut Log file MCI command set File viewer extension MIDI sequence MIDI instrument file Microsoft Mail message file Animation Mini-port driver Microsoft Exchange mail document The Microsoft Network home base
Page 53 of 119
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
MSP NLS PAB PCX PDR PF PIF PPD PRT PST PWL QIC REC REG RLE RMI RTF SCR SET SHB SHS SPD SWP SYS TIF TMP TRN TSP TTF TXT VBX VER VXD WAV WPC WRI XAB Windows Paintbrush picture Natural language services driver Microsoft Exchange personal address book Picture (PCX format) Port driver ICM profile Shortcut to MS-DOS based application PostScript printer description file Printer formatted file (result of Print to File option) Microsoft Exchange personal information store Password list Backup set for Microsoft Backup Windows Recorder file Application registration file Picture (RLE format) MIDI sequence Document (rich text format) Screen saver File set for Microsoft Backup Shortcut into a document Scrap PostScript printer description file Virtual memory storage System file Picture (TIFF format) Temporary file Translation file Windows telephony service provider TrueType font Text document Visual Basic control file Version description file Virtual device driver Sound wave WordPad file converter Windows Write document Microsoft Mail address book
Page 54 of 119
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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 55 of 119
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 users configuration, and information about how to locate the server package. 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=
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 56 of 119
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 \Spool WININIT.EXE \Desktop \Startmen *.INI \Nethood *.GRP 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 CDs 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 users 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 users 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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
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.
Page 57 of 119
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.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 58 of 119
CALLBACK Use in place of FAR PASCAL in application callback routines such as window procs and dialog procs. Same as LPSTR, except used for read-only string pointers. Defined as (const char FAR*). LPCSTR Portable unsigned integer type whose size is determined by host environment (32 bits for Windows UINT NT ). Synonym for unsigned int. Used in place of WORD except in the rare cases where a 16-bit unsigned quantity is desired even on 32-bit platforms. LRESULT Type used for declaration of Window procedure return value. WPARAM Type used for declaration of first general purpose Window procedure parameter. Type used for declaration of second general purpose Window procedure parameter. LPARAM Generic pointer type, equivalent to (void *). Should be used in preference to LPSTR. LPVOID
Utility Macros
WINDOWS.H provides a series of utility macros that are useful for working with the types listed in the previous section. These macros, listed in the following table, help create and extract data from these types. The FIELDOFFSET macro is particularly useful when you need to give the numeric offset of a structure member as an argument. Utility Description MAKELPARAM(low, Combines two 16-bit quantities into an LPARAM. high) MAKELRESULT(low, Combines two 16-bit quantities into an LRESULT. high) Combines a selector and an offset into a FAR VOID* pointer. Useful only for Windows MAKELP(sel, off) 3.x. Extracts the selector part of a far pointer. Returns a UINT. Useful only for Windows 3.x. SELECTOROF(lp) Extracts the offset part of a far pointer. Returns a UINT. Useful only for Windows 3.x. OFFSETOF(lp) FIELDOFFSET(type, Calculates the offset of a member of a data structure. The type is the type of structure, field) and field is the name of the structure member or field.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
HDRVR Driver handle (Windows NT only)
Page 59 of 119
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 60 of 119
steps not strictly required but recommended, especially if you want to produce portable code. These are covered in General Requirements The principal requirement is that you must declare correct handle types and function pointers instead of relying on more general types such as unsigned int and FARPROC. You cannot use one handle type where another is expected. This requirement also means that you may have to change function declarations and use more type casts. For best results, the generic HANDLE type should not be used except where necessary. Consult Using Function Pointers Always declare function pointers with the proper function type (such as DLGPROC or WNDPROC) rather than FARPROC. Youll need to cast function pointers to and from the proper function type when using MakeProcInstance, FreeProcInstance, and other functions that take or return a FARPROC, as shown in the following code: BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); DLGPROC lpfnDlg; lpfnDlg = (DLGPROC)MakeProcInstance(DlgProc, hinst); ... FreeProcInstance((FARPROC)lpfnDlg);
Declaring Functions Within Your Application Make sure all application functions are declared. Placement of all function declarations in an include file is highly recommended because you can more easily scan through your function declarations and look for parameter and return types that should be changed. If you use the /Zg compiler option to create header files for your functions, remember that youll get different results depending on whether or not you have enabled STRICT type checking. With STRICT disabled, all handle types generate the same base type: unsigned short. With STRICT enabled, they generate base types such as HWND __near * or HDC __near *. To avoid conflict, you need to either recreate the header file each time you disable or enable STRICT, or else edit the header file to use the types HWND, HDC, HANDLE, and so on, instead of the base types. If youve copied any function declarations from WINDOWS.H into your source code, they may have changed, and your local declaration may be out of date. Remove your local declaration.
Functions That Require Casts Some functions have generic return types or parameters. For example, a function like SendMessage returns data that may be any number of types, depending on the context. When you see any of these functions in your source code, make sure that you use the correct type cast and that it is as specific as possible. The following table summarizes these functions: Function Comment Cast result to the proper kind of data pointer. LocalLock Cast result to the proper kind of data pointer. GlobalLock Cast result to appropriate data type. GetWindowWord Cast result to appropriate data type GetWindowLong Cast argument as it is passed to function. SetWindowWord
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
SetWindowLong SendMessage DefWindowProc SendDlgItemMessage
Page 61 of 119
Cast argument as it is passed to function. Cast result to appropriate data type; cast to UINT before casting to a handle type. See comment for SendMessage. See comment for SendMessage.
When you call SendMessage, DefWindowProc, or SendDlgItemMessage, you should first cast the result to type UINT. You need to take similar steps for any function that returns LRESULT or LONG, where the result contains a handle. This is necessary for writing portable code because the size of a handle is either 16 bits or 32 bits depending on the version of Windows. The (UINT) cast ensures proper conversion. The following code shows an example in which SendMessage returns a handle to a brush: HBRUSH hbr; hbr = (HBRUSH)(UINT)SendMessage(hwnd, WM_CTLCOLOR, ..., ...);
The CreateWindow Function The CreateWindow and CreateWindowEx hmenu parameter is sometimes used to pass an integer control ID. In this case, you must cast this to an HMENU type: HWND hwnd; int id; hwnd = CreateWindow("Button", "Ok", BS_PUSHBUTTON, x, y, cx, cy, hwndParent, (HMENU)id, // Cast required here hinst, NULL);
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 62 of 119
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 63 of 119
Overview of Changes
The Win32 Application Program Interface (API) uses the flat 32-bit addressing mode, supports source code portability between different processors, and supports high-end capabilities such as security and nonpreemptive multitasking. One of the major design goals of the Win32 API was to minimize the impact on existing code, so that 16-bit applications can be adapted as easily as possible. However, some changes were mandated by the larger address space. Items which have increased to 32 bits include the following: Pointers Window handles Handles to other objects, such as pens, brushes, and menus Message parameters Graphics coordinates These size differences are generally resolved in the header files, but some changes your to source code are necessary. For example, the contents of some message parameters have changed, so you must rewrite the code that handles these messages. The larger size of graphics coordinates also affects a number of function calls.
Introduction
Page 64 of 119
Although the Win32 API was designed to be as compatible as possible, you may need to modify a large amount of source code. To make these changes effectively and efficiently, the following top-down approach is recommended: 1. Build the application with 32-bit development tools, and fix any errors. 2. Replace complex procedures that are difficult to port, as well as procedures written in assembly language, with stub procedures that do nothing except return. 3. Port the code in the main portion of the application, using the steps described in this chapter. 4. Fill in each of the stub procedures, one at a time, with portable code once the main portion of the application compiles and runs correctly. The sections listed describe steps you should take each time you port a 16-bit Windows-based application to the Win32 API: Revising the Window Procedure Declaration Using Proper Data Types Handling Messages Adjusting Function Calls Revising the WinMain Function Revising Dynamic-Link Libraries
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
FAR PASCAL unsigned WORD LONG CALLBACK UINT WPARAM LPARAM
Page 65 of 119
CALLBACK is guaranteed to use whatever calling convention is appropriate for Windows. Meaning is the same, but UINT guarantees portability. WORD is always 16 bits. WPARAM is portable. Not required, but consistent with WPARAM convention
The most significant difference between the Windows 3.x declaration and the Win32 API version is the size difference of the wParam parameter.
Handling Messages
When you move from Windows 3.x to the Win32 API, the information packing changes for some messages. You can either: Revise the code so that it works only for the 32-bit version. Make the message-handling code portable, so that you can easily compile for either the 16-bit or 32-bit environment. We strongly recommend that you create portable code. This section focuses primarily on writing portable versions of the code.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 66 of 119
Handles are now 32 bits in the Win32 API and can therefore no longer be combined with other information and still fit into a 32 bit parameter (lParam), as was possible in Windows 3.x. The handle now occupies all of lParam, so information formerly in the high or low word of lParam must now move to wParam. Because the wParam message parameter is now 32 bits in the Win32 API, it can hold the information that can no longer be held in lParam. The following table shows how this repacking works for WM_COMMAND, one of the messages affected: Environment wParam lParam Windows 3.x id (16-bits) hwnd (16 bits), cmd (16-bits) Win32 API id (16-bits), cmd (16-bits) hwnd (32 bits)
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 67 of 119
The hwndChild data is the same address as lParam; it is either in the low byte or it occupies all of lParam. As long as the address of a handle is always that of lParam, using the cast (HWND)(UINT) correctly extracts the handle: hwndChild = (HWND)(UINT)lParam; Data Changing Location In cases where a piece of data changes packing location in the Win32 API, you need to use an #ifdef statement or you can write your own conversion macros. In this case, the cmd data moves from the high word of wParam to the high word of wParam, so the portable version of the code is: #ifdef WIN32 cmd = HIWORD(wParam); #else cmd = HIWORD(lParam); #endif Often, LOWORD and HIWORD macros create portability problems, because you should usually (except as indicated here) not be extracting parts of data types. // 16-bit: hwnd=LOWORD(lParam);
Each platform has a WINDOWSX.H header file that defines these macros as appropriate. Refer to Handling Messages with Portable Macros for more information.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
WM_CTLCOLOR (16-bit Windows) hdc WM_CTLCOLORtype (Win32 API) (Win32 API) hdc (32 bits) hwnd, type hwnd (32 bits)
Page 68 of 119
Note In the Win32 API, WM_CTLCOLOR is replaced by a series of messages, each corresponding to a different type. To write portable code, use #ifdef to handle this difference. lParam: wParam: Windows 3.x Windows 3.x Win32 API Win32 API Message WM_MENUSELECT (16-bit Windows) cmd flags, hMenu (Win32 API) cmd, flags hMenu (32 bits) WM_MDIACTIVATE (16-bit Windows) fActivate hwndDeactivate, hwndActivate (Win32 API) hwndActivate (32 bits) hwndDeactivate (32 bits) WM_MDISETMENU (16-bit Windows) 0 hMenuFrame, hMenuWindow (Win32 API) hMenuFrame (32 bits) hMenuWindow (32 bits) WM_MENUCHAR (16-bit Windows) char hMenu, fMenu (Win32 API) char, fMenu hMenu (32 bits) (16-bit Windows) msg WM_PARENTNOTIFY id, hwndChild (Win32 API) msg, id hwndChild (32 bits) WM_VKEYTOITEM (16-bit Windows) code item, hwnd (Win32 API) code, item hwnd (32 bits) EM_GETSEL 0 (16-bit Windows) 0 (returns wStart, wEnd) (Win32 API) 0 or lpdwStart 0 or lpdwEnd EM_LINESCROLL (16-bit Windows) 0 nLinesVert, nLinesHorz (32 bits) nLinesVert (32 bits) (Win32 API) mLinesHorz EM_SETSEL (16-bit Windows) 0 wStart, wEnd (Win32 API) wStart (32 bits) wEnd (32 bits) WM_HSCROLL, WM_VSCROLL (16-bit Windows) code pos, hwnd (Win32 API) code, pos hwnd (32 bits)
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
information from these structures: PackDDElParam UnPackDDElParam FreeDDElParam
Page 69 of 119
Graphics Functions
Most of the Windows 3.x functions that must be replaced return packed x- and y-coordinates. In Windows 3.x, the x- and y-coordinates are 16 bits each and are packed into the 32-bit DWORD function return value, the largest valid size. In the Win32 API, the coordinates are 32 bits each, totaling 64 bits, and are thus too large to fit into a single return value. Each Windows 3.x function is replaced by a function with the same name, but with an Ex suffix added. The Ex functions pass the x- and y-coordinates using an additional parameter instead of a return value. These new functions are supported by both the Win32 API and Windows 3.x. Windows 3.x implements these functions with a static library, in order that source code compiled with the new calls will also function in Windows 3.x. The problematic graphics functions fall into two groups. The first group, functions that set coordinates, are shown below with the Win32 API versions: Windows 3.x function Win32 API version of function MoveTo MoveToEx OffsetViewportOrg OffsetViewportOrgEx OffsetWindowOrg OffsetWindowOrgEx ScaleViewportExt ScaleViewportExtEx ScaleWindowExt ScaleWindowExtEx SetBitmapDimension SetBitmapDimensionEx SetMetaFileBits SetMetaFileBitsEx SetViewportExt SetViewportExtEx SetWindowExt SetWindowExtEx SetWindowOrg SetWindowOrgEx Each of the functions in the first column returns a value, although application code frequently ignores it. However,
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 70 of 119
even if you do not care about the return value, you must still replace the old function call by the new form. The old functions are not supported in the Win32 API. Each Ex function includes an additional parameter that points to a location to receive data. After the function call, this data provides the same information as the corresponding functions return value. If you do not need this information, you can pass NULL to this parameter. Under Windows 3.x, a call to the MoveTo function can be written as follows: MoveTo( hDC, x, y ); In the portable version supported by all versions of Windows, the call to MoveTo is rewritten as follows. Note that the information returned by MoveTo under Windows 3.x is still ignored: MoveToEx( hDC, x, y, NULL ); As a general rule, pass NULL as the last parameter unless you need to use the x- and y-coordinates returned by the Windows 3.x version. In the latter case, use the procedure outlined in the next few paragraphs. The second group of functions consists of functions in which the application code normally does use the return value. They are listed in the following table. Windows 3.x function Portable version of function GetAspectRatioFilter GetAspectRatioFilterEx GetBitmapDimension GetBitmapDimensionEx GetBrushOrg GetBrushOrgEx GetCurrentPosition GetCurrentPositionEx GetTextExtent GetTextExtentPoint GetTextExtentEx GetTextExtentExPoint GetViewportExt GetViewportExtEx GetViewportOrg GetViewportOrgEx GetWindowExt GetWindowExtEx GetWindowOrg GetWindowOrgEx The GetTextExtent function uses the Point suffix, because there is already a Windows 3.1 extended function GetTextExtentEx. Therefore, the Point suffix is added to the functions GetTextExtent and GetTextExtentEx, to name the portable versions for each. As with the first group of functions, the Ex (and Point) versions each add an additional parameter: a pointer to a POINT or SIZE structure to receive x/y coordinates. Because this structure is always the appropriate size for the environment, so you can write portable code by: Declaring a local variable of type POINT or SIZE, as appropriate. Passing a pointer to this structure as the last parameter to the function. Calling the function. The function responds by filling the structure with the appropriate information. For example, the Windows 3.x version call to GetTextExtent extracts the x- and y-coordinates from a DWORD return value (stored in a temporary variable, dwXY): DWORD dwXY; dwXY = GetTextExtent( hDC, szLabel1, strlen( szFoo ) ); rect.left = 0; rect.bottom = 0;
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
rect.right = LOWORD(dwXY); rect.top = HIWORD(dwXY); InvertRect( hDC, &rect );
Page 71 of 119
The portable version passes a pointer to a temporary SIZE structure, and then it extracts data from the structure: SIZE sizeRect; GetTextExtentPoint( hDC, szLabel1, strlen( szLabel1 ), &sizeRect ); rect.left = 0; rect.bottom = 0; rect.right = sizeRect.cx; rect.top = sizeRect.cy; InvertRect( hDC, &rect );
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
hwndParent = (HWND)GetWindowLong(hWnd, GWL_HWNDPARENT); #else hwndParent = (HWND)GetWindowWord(hWnd, GWW_HWNDPARENT); #endif
Page 72 of 119
In the case of GWW_HWNDPARENT, you can avoid calls to GetWindowLong and GetWindowWord altogether, and instead use a single call to a new function, GetParent. This function returns a handle of the appropriate size. The following example illustrates a call to GetParent that has the same results as the #ifdef statements shown in the previous example: hwndParent = GetParent( hWnd ); Remember that offsets may change for private data that you store in the Window structure. You should review this code carefully and recalculate offsets for Win32-based applications, noting that some data types, such as handles, increase in size.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
5BH 5CH 5CH 67H Create New File Lock Unlock Set Handle Count CreateFile LockFile UnlockFile SetHandleCount
Page 73 of 119
File Operations
Fixed-length buffers for filenames and environment strings may need to be increased in size. Windows NT and Windows 95 support long filenames, rather than the 8.3 format supported by MS-DOS. You can make code more portable by allocating longer buffers or by using dynamic memory allocation. If you want to conserve memory under Windows 3.x, use #ifdef statements to allocate buffers of the proper length for the environment. Another area in which you might need to make changes is low-level file I/O. In porting Windows 3.x code, some developers have chosen to change from using the Windows API file I/O functions (such as _lopen and _lread) to using the C run-time low-level I/O functions (such as _open and _read). All versions of the Windows API support binary mode only, not text mode, but the C run-time calls use text mode by default. Therefore, when changing from the Windows file I/O to the C run-time versions, open files in binary mode by doing one of the following: Link with BINMODE.OBJ, which changes the default mode for all file-open operations. Open the individual files with _O_BINARY flag set. Use setmode to change an open file to _O_BINARY.
Far-Pointer Functions
Windows 3.x provides functions for memory and file manipulation using far pointers, which have the form _fxxxx. In the Win32 API, these functions are replaced by similarly named functions of the form xxxx, because there is no need for far pointers in Win32-based applications. In other words, the _f prefix was dropped from the name. The 32-bit WINDOWSX.H file defines the _fxxxx function names so that the _fxxxx function names are equated to the corresponding functions that are still supported. This means that as long as you include WINDOWSX.H, you dont have to rewrite calls to these functions. Some of the definitions are: #define #define #define #define _fmemcpy(x,y,z) _fstrcpy(x,y) _fstrcmp(x,y) _fstrcat(x,y) memcpy(x,y,z) strcpy(x,y) strcmp(x,y) strcat(x,y)
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
For example, Windows 3.x code might contain the following function call: DlgDirSelect( hDlg, lpString, nIDListBox ); This line of code should be replaced by the following call to DlgDirSelectEx: DlgDirSelectEx( hDlg, lpString, sizeof(lpString), nIDListBox );
Page 74 of 119
Initializing Instances
The hPrevInstance parameter always returns NULL in the Win32 API. This causes each instance of an application to act as though it were the only instance running. The application must register the window class, and it cannot access data used by other instances, except through standard interprocess communication techniques such as shared memory or DDE. Calls to GetInstanceData must be replaced with one of these techniques. Source code for Windows 3.x normally tests hPrevInstance to see if another instance of the application is already running; if the value is NULL this indicates there is no previous instance, so the code registers the window class. This code is automatically portable and needs no change: the result in a Win32-based application is that it always registers the window class, which is correct behavior. Some applications must know if other instances are running. Sometimes this is because data sharing is required. More frequently, it is because only one instance of the application should run at a time.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 75 of 119
Applications cannot use hPrevInstance to test for previous instances in a Win32-based application. An alternative method must be used to locate a previous instance, such as: Creating and testing for the existence of a named mutex. Creating a unique named pipe Calling FindWindow with the window class and name. Because a second instance of the application could be started and execute a call to FindWindow before the first instance has created its window, it is better to use a named object.
The initialization function in a Win32-based DLL includes the hinst parameter, but does not include the other parameters, for the reasons described in the following table. Parameter Comment wDataSeg Not needed in Win32-based applications; memory model is flat, not segmented. cbHeapSize All calls to local memory management functions operate on the default heap
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 76 of 119
lpszCmdLine The command line can be obtained through a call to the GetCommandLine function. The initialization function in the Win32 API, DllEntryPoint, has the following prototype: BOOL APIENTRY DllEntryPoint( HINSTANCE hInstDLL, // handle to DLL module DWORD fdwReason, // reason for calling function LPVOID lpvReserved // reserved ); The fdwReason parameter indicates whether initialization or termination is taking place, and whether a process or a thread is involved. For example, when a process first loads a DLL, DllEntryPoint is called with a DLL_PROCESS_ATTACH notification: it is assumed that the process has one thread to begin with. When additional threads are created, the function is called with a DLL_THREAD_ATTACH notification. The body of your DllEntryPoint should contain a statement similar to this one: switch( dwReason) { case DLL_PROCESS_ATTACH: ... case DLL_THREAD_ATTACH: ... case DLL_THREAD_DETACH: ... case DLL_PROCESS_DETACH: ... } Your initialization function should return 1 to indicate success. Returning NULL indicates failure. You do not need a WEP function.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Profile Strings and .INI Files Focus, Mouse Capture, and Localized Input Shared Graphical Objects Memory and Pointers Structure Alignment Ranges and Promotions
Page 77 of 119
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 78 of 119
function returns NULL. For example, you call GetFocus and another thread has the focus. Note that its possible for a call to GetFocus to return NULL even though an earlier call to SetFocus successfully set the focus. Simliar considerations apply to GetCapture and GetActiveWindow. The Set functions can only specify a window created by the current thread. If you attempt to pass a window handle created by another thread, the call to the Set function fails. Mouse Capture Mouse capture is also affected by localized input queues. If the mouse is captured on mouse down, the window capturing the mouse receives mouse input until the mouse button is released, as in Windows 3.x. But if the mouse is captured while the mouse button is up, the window receives mouse input only as long as the mouse is over that window or another window created by the same thread.
Such code does not work properly in a Win32-based application. But standard pointer constructs, such as the following, always result in portable code: ptr1 = malloc(); ptr2 = ptr1[i]; // Set ptr1 to start of memory block // Place offset of array element
Here are some other guidelines for dealing with pointers: All pointers, including those that access the local heap, are 32 bits in a Win32-based application. Addresses never wrap, as they can with the low word in segmented addressing; for example, in Windows 3.x,
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
an address can wrap from 1000:FFFF to 1000:0000.
Page 79 of 119
Structures that hold near pointers in Windows 3.x must be revised because all pointers are 32 bits in a Win32based application. This may affect code that uses constants to access structure members, and it may also affect alignment.
Structure Alignment
Applications should generally align structure members at addresses that are natural for the data type and the processor involved. For example, a 4-byte data member should have an address that is a multiple of four. This principle is especially important when you write code for porting to multiple processors. A misaligned 4-byte data member, which is on an address that is not a multiple of four, causes a performance penalty with an 80386 processor and a hardware exception with a RISC processor. In the latter cases, although the exception is handled by the system, the performance penalty is significantly greater. Alignment problems can be avoided by setting compiler options or adjusting your structure definitions to meet the alignment requirements. Use the following guidelines to ensure proper alignment for all processors: Type Alignment Align on byte boundaries char Align on even byte boundaries short (16-bit) int and long (32-bit) Align on 32-bit boundaries Align on 32-bit boundaries float Align on 64-bit boundaries double structures Align on 32-bit boundaries
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Writing message crackers for user-defined messages Adapting message crackers to special cases Using control message functions
Page 80 of 119
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 81 of 119
return HANDLE_WM_THIS ( hwnd, wParam, lParam, MyWnd_OnThis );
... } LRESULT MyWnd_OnThis ( HWND hwnd, HDC thisHdc, WORD thisData ) { // Place code to handle message here } The parameters to MyWnd_OnThis (after hwnd, which is always the first parameter) consist of information directly usable by your code: thisHdc and thisData. The macro HANDLE_WM_THIS translates wParam and lParam into thisHdc and thisData as it makes the function call. The following general steps summarize how to use message crackers: 1. Declare a prototype for each message-handling function. 2. In the windows procedure, call the message handler. Use either a message decoder (such as HANDLE_WM_CREATE) or the HANDLE_MSG macro. 3. Write the message handler. Use a message forwarder such as FORWARD_WM_CREATE to call the default message procedure.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
For example, you could place the following macros in your code:
Page 82 of 119
switch( msg ) { case WM_CREATE: return HANDLE_WM_CREATE( hwnd, wParam, lParam, MyWnd_OnCreate ); case WM_PAINT: return HANDLE_WM_PAINT( hwnd, wParam, lParam, MyWnd_OnPaint ); case WM_MOUSEMOVE: return HANDLE_WM_MOUSEMOVE( hwnd, wParam, lParam, MyWnd_OnMouseMove ); . . . Alternatively, you can use the generic HANDLE_MSG macro, which generates the same code as the previous example, but saves space: switch( msg ) { HANDLE_MSG( hwnd, WM_CREATE, MyWnd_OnCreate ); HANDLE_MSG( hwnd, WM_PAINT, MyWnd_OnPaint ); HANDLE_MSG( hwnd, WM_MOUSEMOVE, MyWnd_OnMouseMove ); . . . HANDLE_MSG assumes that you use the names wParam and lParam in the window procedure parameter list. You cannot use this macro if you have given these parameters other names.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 83 of 119
The header file, MYAPP.H, consists of function prototypes, including prototypes for the message handlers. Note how each message handler has its own parameter list, which is customized to best represent the information packed in the corresponding message: // MYAPP.H // Window procedure prototype LONG WINAPI MyWnd_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); // Default message handler #define MyWnd_DefProc DefWindowProc
// MyWnd class message handler functions, declared in a .h file: // void MyWnd_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags); void MyWnd_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags); void MyWnd_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags); The rest of the code in this example is in MYAPP.C, which contains the window procedure and the individual message handlers. With message crackers, the function of the window procedure is principally to route each message to the appropriate handler. Both the WM_LBUTTONDOWN and WM_LBUTTONDBLCLK messages map to the MyWnd_OnLButtonDown procedure. This mapping is one of the special cases of message handling described in Handling Special Cases of Messages. // MYAPP.C ------------------------------------------------------------------------
// MyWnd window procedure implementation. // LONG WINAPI MyWnd_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM Param) { switch (msg) { HANDLE_MSG(hwnd, WM_MOUSEMOVE,MyWnd_OnMouseMove); HANDLE_MSG(hwnd, WM_LBUTTONDOWN, MyWnd_OnLButtonDown); HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK, MyWnd_OnLButtonDown); HANDLE_MSG(hwnd, WM_LBUTTONUP, MyWnd_OnLButtonUp); default: return MyWnd_DefProc(hwnd, msg, wParam, lParam); } } // Message handler function implementations: // void MyWnd_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags) { . . . return FORWARD_WM_MOUSEMOVE( hwnd, x, y, keyFlags, MyWnd_DefProc); } void MyWnd_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) { . . . return FORWARD_WM_LBUTTONDOWN( hwnd, fDoubleClick, x, y, keyFlags, MyWnd_DefProc); } void MyWnd_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags) {
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
.
Page 84 of 119
. . return FORWARD_WM_LBUTTONUP( hwnd, x, y, keyFlags, MyWnd_DefProc); } Note that the symbol MyWnd_DefProc is defined to represent DefWindowProc. The purpose of this definition is to make code more reusable. This approach assumes you have a similar definition in each application. For example, in an MDI child control procedure, you would have this definition: #define MyWnd_DefProc DefMDIChildProc
If you then copied your message handler to the MDI procedure, you would only need to change the prefix in MyWnd_DefProc to make the code you copied work correctly. Conversely, if your code used the explicit call to DefWindowProc, it could create a bug that would be difficult to track down when copied to the MDI code.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 85 of 119
is a constant (such as WM_USER+100), you can use HANDLE_MSG with the message in a switch statement. However, if the message is registered with RegisterWindowMessage, it assigns a number at run time. In this situation, you cant use HANDLE_MSG, because variables cannot be used as case values. You must handle the message separately, in an if statement: // In MyWnd class initialization code: // UINT WM_NEWMESSAGE= 0; WM_NEWMESSAGE= RegisterWindowMessage("WM_NEWMESSAGE"); . . . // In MyWnd_WndProc(): window procedure: // LONG WINAPI MyWnd_WndProc(HWND hwnd, WORD msg, WPARAM wParam, LPARAM lParam) { if (msg == WM_NEWMESSAGE) HANDLE_WM_NEWMESSAGE(hwnd, wParam, lParam, MyWnd_OnNewMessage); switch (msg) { HANDLE_MSG(hwnd, WM_MOUSEMOVE, MyWnd_OnMouseMove); . . . }
Dialog Procedures
Dialog procedures return a BOOL value to indicate whether the message was processed. (Window procedures, in contrast, return a LONG value rather than a BOOL.) Therefore, to adapt a message cracker to dialog-procedure code, you must call the message handler and cast the value to BOOL. Because you have to insert the (BOOL) cast, you cant use HANDLE_MSG. You must invoke the messagedecoder macro explicitly. Heres an example that shows how youd use message crackers in a dialog procedure: BOOL MyDlg_OnInitDialog(HWND hwndDlg, HWND hwndFocus, LPARAM lParam); void MyDlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify); BOOL WINAPI MyDlg_DlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { // // Since HANDLE_WM_INITDIALOG returns an LRESULT, // we must cast it to a BOOL before returning. // case WM_INITDIALOG: return (BOOL)HANDLE_WM_INITDIALOG(hwndDlg, wParam, lParam, MyDlg_OnInitDialog); case WM_COMMAND:
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
HANDLE_WM_COMMAND(hwndDlg, wParam, lParam, MyDlg_OnCommand); return TRUE; break; default: return FALSE; } }
Page 86 of 119
Window Subclassing
When you use message crackers with a subclassed window procedure, the strategy described earlier for using message forwarders does not work. Recall that this strategy involves the following macro call: return FORWARD_msg( parmlist, defaultMsgProc ); This use of a message forwarder (FORWARD_msg) calls defaultMsgProc directly. But in a subclassed window procedure, you must call the window procedure of the superclass by using the API function CallWindowProc. The problem is that FORWARD_msg calls the defaultMsgProc with four parameters, but CallWindowProc needs five parameters. The solution is to write an intermediate procedure. For example, the intermediate procedure could be named test_DefProc: FORWARD_WM_CHAR(hwnd, ch, cRepeat, test_DefProc); The test_DefProc function calls CallWindowProc and prepends the address of the superclass function (in this case, test_lpfnwpDefProc) to the parameter list: LONG test_DefProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { return CallWindowProc(test_lpfnwpDefProc, hwnd, msg, wParam, lParam); } You need to write just one such procedure for each subclassed window in your application. Each time you use a message forwarder, you give this intermediate procedure as the function address instead of DefWindowProc. The following example code shows the complete context: // Global variable that holds the previous window proc address of // the subclassed window: // WNDPROC test_lpfnwpDefProc = NULL; // Code fragment to subclass a window and store previous wndproc value: // void Subclasstest(HWND hwndtest) { extern HINSTANCE g_hinsttest; // Global application instance handle // SubclassWindow() is a macro API that calls SetWindowLong() // as appropriate to change the window proc of hwndtest. // test_lpfnwpDefProc = SubclassWindow(hwndtest, (WNDPROC)MakeProcInstance( (FARPROC)test_WndProc, g_hinsttest)); . . .} // Default message handler function // // This function invokes the superclasses' window procedure. It // must be declared with the same signature as any window proc, // so it can be used with the FORWARD_WM_* macros.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 87 of 119
// LONG test_DefProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { return CallWindowProc(test_lpfnwpDefProc, hwnd, msg, wParam, lParam); } // test window procedure. Everything here is the same as in the // normal non-subclassed case: the differences are encapsulated in // test_DefProc. // LONG WINAPI test_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { HANDLE_MSG(hwnd, WM_CHAR, test_OnChar); . . . default: // // Be sure to call test_DefProc(), NOT DefWindowProc()! // return test_DefProc(hwnd, msg, wParam, lParam); } } // Message handlers // void test_OnChar(HWND hwnd, UINT ch, int cRepeat) { if (ch == testvalue) { // handle it here } else { // Forward the message on to test_DefProc // FORWARD_WM_CHAR(hwnd, ch, cRepeat, test_DefProc); } }
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 88 of 119
// "test" window class was registered with cbWndExtra = sizeof(test*), so we // can use a window word to store back pointer. Window properties can also // be used. // // These macros get and set the pointer to the instance data corresponding to the // window. Use GetWindowWord or GetWindowLong as appropriate based on the default // size of data pointers. // #ifdef WIN32 #define test_GetPtr(hwnd) (test*)GetWindowLong((hwnd), 0) #define test_SetPtr(hwnd, ptest) (test*)SetWindowLong((hwnd), 0, (LONG)(ptest)) #else #define test_GetPtr(hwnd) (test*)GetWindowWord((hwnd), 0) #define test_SetPtr(hwnd, ptest) (test*)SetWindowWord((hwnd), 0, (WORD)(ptest)) #endif // Default message handler #define test_DefProc DefWindowProc // Message handler functions, declared with a test* as their first argument, // rather than an HWND. Other than that, their signature is identical to // that shown in WINDOWSX.H. // BOOL test_OnCreate(test* ptest, CREATESTRUCT FAR* lpcs); void test_OnPaint(test* ptest); // // Code to register the test window class: // BOOL test_Init(HINSTANCE hinst) { WNDCLASS cls; cls.hCursor = ...; cls.hIcon = ...; cls.lpszMenuName = ...; cls.hInstance = hinst; cls.lpszClassName = "test"; cls.hbrBackground = ...; cls.lpfnWndProc = test_WndProc; cls.style = CS_DBLCLKS; cls.cbWndExtra = sizeof(test*); // room for instance data ptr cls.cbClsExtra = 0; return RegisterClass(&cls); } // The window proc for class "test". This demonstrates how instance data is // attached to a window and passed to the message handler functions. // LRESULT CALLBACK test_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { test* ptest = test_GetPtr(hwnd); if (ptest == NULL) { // If we're creating the window, then try to allocate it. // if (msg == WM_NCCREATE) { // Create the instance data structure, set up the hwnd backpointer // field, and associate it with the window. // ptest = (test*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(test)); // If an error occured, return 0L to fail the CreateWindow call. // This will cause CreateWindow() to return NULL. // if (ptest == NULL) return 0L; ptest->hwnd = hwnd; test_SetPtr(hwnd, ptest); // NOTE: the rest of the test structure should be initialized // inside of Template_OnCreate() (or Template_OnNCCreate()). Further // creation data may be accessed through the CREATESTRUCT FAR* parameter.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
// } else {
Page 89 of 119
// It turns out WM_NCCREATE is NOT necessarily the first message // received by a top-level window (WM_GETMINMAXINFO is). // Pass messages that precede WM_NCCREATE on through to // test_DefProc // return test_DefProc(hwnd, msg, wParam, lParam); } } if (msg == WM_NCDESTROY) { LocalFree((HLOCAL)ptest); ptest = NULL; test_SetPtr(hwnd, NULL); } switch (msg) { HANDLE_MSG(ptest, WM_CREATE, test_OnCreate); HANDLE_MSG(ptest, WM_PAINT, test_OnPaint); ... default: return test_DefProc(hwnd, msg, wParam, lParam); } }
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 90 of 119
The source code below uses two control message functions, Edit_GetLineCount and Edit_GetLine, to perform the same task. This version of the code is shorter, easier to read, doesnt generate compiler warnings, and doesnt have any non-portable casts: void PrintLines(HWND hwndEdit, WHND hwndDisplay) { int line; int lineLast = Edit_GetLineCount(hwndEdit); for (line = 0; line < lineLast; line++) { int cch; char ach[80]; cch = Edit_GetLine(hwndEdit, line, ach, sizeof(ach)); PrintInWindow(ach, hwndDisplay); } } The control message API functions are listed in the table below. For more information, refer to the macro definitions in WINDOWSX.H and the documentation for the corresponding window message. Control Message API Functions Control Group Static Text Controls:
Functions Static_Enable(hwnd, fEnable) Static_GetIcon(hwnd, hIcon) Static_GetText(hwnd, lpch, cchMax) Static_GetTextLength(hwnd) Static_SetIcon(hwnd, hIcon) Static_SetText(hwnd, lpsz) Button_Enable(hwnd, fEnable) Button_GetCheck(hwnd) Button_GetState(hwnd) Button_GetText(hwnd, lpch, cchMax) Button_GetTextLength(hwnd) Button_SetCheck(hwnd, check) Button_SetState(hwnd, state) Button_SetStyle(hwnd, style, fRedraw) Button_SetText(hwnd, lpsz) Edit_CanUndo(hwnd) Edit_EmptyUndoBuffer(hwnd) Edit_Enable(hwnd, fEnable) Edit_FmtLines(hwnd, fAddEOL) Edit_GetFirstVisible(hwnd) Edit_GetHandle(hwnd) Edit_GetLine(hwnd, line, lpch, cchMax) Edit_GetLineCount(hwnd) Edit_GetModify(hwnd) Edit_GetRect(hwnd, lprc) Edit_GetSel(hwnd) Edit_GetText(hwnd, lpch, cchMax) Edit_GetTextLength(hwnd) Edit_LimitText(hwnd, cchMax) Edit_LineFromChar(hwnd, ich)
Button Controls:
Edit Controls:
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 91 of 119
Edit_LineIndex(hwnd, line) Edit_LineLength(hwnd, line) Edit_ReplaceSel(hwnd, lpszReplace) Edit_Scroll(hwnd, dv, dh) Edit_SetHandle(hwnd, h) Edit_SetModify(hwnd, fModified) Edit_SetPasswordChar(hwnd, ch) Edit_SetRect(hwnd, lprc) Edit_SetRectNoPaint(hwnd, lprc) Edit_SetSel(hwnd, ichStart, ichEnd) Edit_SetTabStops(hwnd, cTabs, lpTabs) Edit_SetText(hwnd, lpsz) Edit_SetWordBreak(hwnd, lpfnWordBreak) Edit_Undo(hwnd)
ScrollBar_Enable(hwnd, flags) ScrollBar_GetPos(hwnd) ScrollBar_GetRange(hwnd, lpposMin, lpposMax) ScrollBar_SetPos(hwnd, pos, fRedraw) ScrollBar_SetRange(hwnd, posMin, posMax, fRedraw) ScrollBar_Show(hwnd, fShow) ListBox_AddFile(hwnd, lpszFilename) ListBox_AddItemData(hwnd, data) ListBox_AddString(hwnd, lpsz) ListBox_DeleteString(hwnd, index) ListBox_Dir(hwnd, attrs, lpszFileSpec) ListBox_Enable(hwnd, fEnable) ListBox_FindItemData(hwnd, indexStart, data) ListBox_FindString(hwnd, indexStart, lpszFind) ListBox_GetAnchorIndex(hwnd) ListBox_GetCaretIndex(hwnd) ListBox_GetCount(hwnd) ListBox_GetCurSel(hwnd) ListBox_GetHorizontalExtent(hwnd) ListBox_GetItemData(hwnd, index) ListBox_GetItemHeight(hwnd, index) (1) ListBox_GetItemRect(hwnd, index, lprc) ListBox_GetSel(hwnd, index) ListBox_GetSelCount(hwnd) ListBox_GetSelItems(hwnd, cItems, lpIndices) ListBox_GetText(hwnd, index, lpszBuffer) ListBox_GetTextLen(hwnd, index) ListBox_GetTopIndex(hwnd) ListBox_InsertItemData(hwnd, lpsz, index)
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 92 of 119
ListBox_InsertString(hwnd, lpsz, index) ListBox_ResetContent(hwnd) ListBox_SelectItemData(hwnd, indexStart, data) ListBox_SelectString(hwnd, indexStart, lpszFind) ListBox_SelItemRange(hwnd, fSelect, first, last) ListBox_SetAnchorIndex(hwnd, index) ListBox_SetCaretIndex(hwnd, index) ListBox_SetColumnWidth(hwnd, cxColumn) ListBox_SetCurSel(hwnd, index) ListBox_SetHorizontalExtent(hwnd, cxExtent) ListBox_SetItemData(hwnd, index, data) ListBox_SetItemHeight(hwnd, index, cy) (1) ListBox_SetSel(hwnd, fSelect, index) ListBox_SetTabStops(hwnd, cTabs, lpTabs) ListBox_SetTopIndex(hwnd, indexTop)
ComboBox_AddItemData(hwnd, data) ComboBox_AddString(hwnd, lpsz) ComboBox_DeleteString(hwnd, index) ComboBox_Dir(hwnd, attrs, lpszFileSpec) ComboBox_Enable(hwnd, fEnable) ComboBox_FindItemData(hwnd, indexStart, data) ComboBox_FindString(hwnd, indexStart, lpszFind) ComboBox_GetCount(hwnd) ComboBox_GetCurSel(hwnd) ComboBox_GetDroppedControlRect (hwnd, lprc) (1) ComboBox_GetDroppedState(hwnd) (1) ComboBox_GetEditSel(hwnd) ComboBox_GetExtendedUI(hwnd) (1) ComboBox_GetItemData(hwnd, index) ComboBox_GetItemHeight(hwnd) ComboBox_GetLBText(hwnd, index, lpszBuffer) ComboBox_GetLBTextLen(hwnd, index) ComboBox_GetText(hwnd, lpch, cchMax) ComboBox_GetTextLength(hwnd) ComboBox_InsertItemData(hwnd, index, data) ComboBox_InsertString(hwnd, index, lpsz) ComboBox_LimitText(hwnd, cchLimit)
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 93 of 119
ComboBox_ResetContent(hwnd) ComboBox_SelectItemData(hwnd, indexStart, data) ComboBox_SelectString(hwnd, indexStart, lpszSelect) ComboBox_SetCurSel(hwnd, index) ComboBox_SetEditSel(hwnd, ichStart, ichEnd) ComboBox_SetExtendedUI(hwnd, flags) (1) ComboBox_SetItemData(hwnd, index, data) ComboBox_SetItemHeight(hwnd, cyItem) (1) ComboBox_SetText(hwnd, lpsz) ComboBox_ShowDropdown(hwnd, fShow)
1 Supported only for Win32, not for Windows 3.x. These functions are not available if you define the symbol WINVER as equal to 0x0300, on the command line or with a #define statement.
Generic Thunks
Windows NT supports running 16-bit Windows-based applications using a technology referred to as WOW (Windows on Win32). Each 16-bit application is run as a thread of a 32-bit process. Windows 95 also supports running 16-bit Windows-based applications. They run as 16-bit processes. Neither Windows NT or Windows 95 allow direct mixing of 16-bit code and 32-bit code in the same process. Both platforms support IPC mechanisms, such as DDE, RPC, OLE, named pipes, and WM_COPYDATA, which you can use for communication between 16-bit code and 32-bit code. However, there are occasions when it is necessary to call a function in a Win32-based DLL (including functions in the system DLLs) from a 16-bit application. Generic thunks provide a mechanism for 16-bit applications to call functions in Win32-based DLLs.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Process Context
Page 94 of 119
In generic thunking, the Win32-based DLL is run in the context of the process that loaded it, namely the 16-bit Windows-based application. The GDI, dialog box, message box, and message functions work within 32-bit code loaded in the context of a 16bit process. However, not all base features are supported in the context of a 16-bit process. In general, 32-bit code loaded by 16-bit processes can use the Win32 heap functions, memory-mapped file functions, file functions, and functions involving the current process and thread. You should avoid using third party Win32-based DLLs, unless you are sure they work safely in a 16 bit-environment. Windows 95: Under Windows 95, there are a few additional limitations for Win32-based DLLs loaded by a 16-bit application:
The DLL uses the stack reserved by the 16-bit application, which is much smaller than the 1MB default stack used by a Win32-based application (generally between 5 and 45K).
The DLL cannot create new threads. Certain Win32 functions, such as those supporting the common dialog boxes or those supporting console applications, create threads on behalf of the calling application. Therefore, these functions cannot be used in a Win32-based DLL loaded by a 16-bit process.
Introduction
Page 95 of 119
One approach for implementing generic thunks is to isolate thunking code into DLLs. The advantage is that you can easily discard the thunking code when it is no longer needed. You can also create separate DLLs for each platform, to isolate platform-specific differences. Another approach for isolating platform differences is to detect the platform at run time and call the appropriate functions for each platform. The examples in this overview demonstrate the required steps for a 16-bit Windows-based application named APP16 call the MyPrint routine from the Win32-based DLL named DLL32. These examples also give hints for isolating thunking code into a DLL named DLL16. Declaring the DLL function Loading the Win32-based DLL Getting the address of the DLL function Calling the DLL function Freeing the Win32-based DLL You can also use generic thunks to call back into the 16-bit side of the thunk from the 32-bit side of the thunk (generic callback). For more information, see WOWCallback16. Note You can also use generic thunks to translate pointers outside of thunks. For more information, see, Translating 16:16 Pointers.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
}
Page 96 of 119
If you are isolating your thunking code into DLL16, you can put the call to LoadLibraryEx32W in the LibMain function of the DLL16 code. The instance handle is stored in the following global variable: DWORD ghLib; When linking the 16-bit code, you need to indicate that the generic thunking functions will be imported from the system kernel. For example, using Microsoft Visual C++, you would create an IMPORTS section in the module definition (.DEF) file for APP16, as follows. IMPORTS kernel.LoadLibraryEx32W kernel.FreeLibrary32W kernel.GetProcAddress32W kernel.GetVDMPointer32W kernel.CallProc32W kernel.CallProcEx32W
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 97 of 119
These examples call MyPrint, passing two arguments, a string and a window handle. All parameters must be 32bit values. Therefore, the string is declared using a FAR pointer, as shown here: char FAR *TestString = "Hello there"; You must convert the 16-bit window handle to a 32-bit window handle using the WOWHandle32 function, as shown here: // Convert the window handle. DWORD hWnd32; hWnd32 = WOWHandle32(hWnd, WOW_TYPE_HWND); This first example uses CallProcEx32W. // Call the MyPrint routine in the Win32-based DLL CallProcEx32W( 2 | CPEX_DEST_STDCALL, 2, hProc, (DWORD) TestString, hWnd32); This next example uses CallProc32W: // Call the MyPrint routine in the Win32-based DLL CallProc32W( (DWORD) TestString, hWnd32, hProc, 2, 2 | CPEX_DEST_STDCALL); A mask of 2 (0x10) is given because we want to pass TestString by reference and the handle by value. The system translates the pointer for us. If you are isolating your thunking code into DLL16, put the call to CallProc32W or CallProcEx32W in the MyPrint function of the DLL16 code.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
functions, see the 16-bit Windows SDK documentation. Windows 95:
Page 98 of 119
If you use GetVDMPointer32W or WOWGetVDMPointer and the affected 16:16 pointer represents a movable global memory manager block, it is important that you first call the GlobalFix or GlobalWire function on the segment portion of the pointer. If you do not, the 16-bit global memory manager can move the block while your process is executing 32-bit code. If this happens, the linear address returned by GetVDMPointer32W or WOWGetVDMPointer will become invalid. The debugging version of Windows 95 generates warnings about calls to GetVDMPointer32W on unfixed segments. The WOWGetVDMPointerFix function is similar to WOWGetVDMPointer, but ensures that the memory pointed to will not be moved by the global memory compacter until the WOWGetVDMPointerUnfix function has been called. WOWGetVDMPointerFix performs an implicit GlobalFix operation on the selector, if necessary. If the selector is allocated as a fixed block or if it is not from the global memory manager, no special action is taken. You should use this function instead of calling GlobalFix separately, because it is easier to use and is faster than calling both GlobalFix and WOWGetVDMPointer. WOWGetVDMPointerUnfix takes a 16:16 address and undoes the effect of WOWGetVDMPointerFix on the segment (the offset portion is ignored). This function should be called once the linear address is no longer needed to avoid fragmentation. It is faster than the GlobalUnfix function and correctly handles (that is, ignores) selectors that are not from the 16-bit global memory manager. Windows NT: While you are executing 32-bit code called through a generic thunk, the 16-bit side of the thunk is completely blocked until you return or yield. Therefore, in most cases, you do not need to fix or wire the memory. Therefore, WOWGetVDMPointerFix is identical to WOWGetVDMPointer (it does not call GlobalFix) and WOWGetVDMPointerUnfix has no effect under Windows NT. If you are targeting only Windows NT and your 32-bit code yields the message system (by calling functions such as SendMessage, BroadcastSystemMessage, GetMessage, PeekMessage, MessageBox, or DialogBox), you should either call GlobalFix or GlobalWire ahead of time on the 16-bit side or refresh your 32-bit pointers after the yielding function call has completed by calling WOWGetVDMPointer. If you are targeting both Windows NT and Windows 95, there are two approaches that you can use. The easiest approach is to have the 16-bit side of the thunk first fix all of the segments in memory using GlobalFix or GlobalWire. In the 32-bit code, use WOWGetVDMPointer, rather than WOWGetVDMPointerFix, because the segments are already fixed in memory. After the 32-bit code returns, call GlobalFix or GlobalUnwire in the 16-bit code. This guarantees that your 32-bit pointers remain valid, regardless of the platform, even if the 16-bit global memory manager compacts the global heap. The drawback to this approach is that many segments can be left fixed in memory for extended periods of time, potentially causing out-of-memory conditions due to memory fragmentation. The most efficient approach that still works on both platforms requires that you use WOWGetVDMPointerFix and WOWGetVDMPointerUnfix. On Windows NT, the 32-bit pointers can still be affected by 16-bit memory movement if the 32-bit code yields the message system. After each call that might yield the messaging system, discard your 32-bit pointers using WOWGetVDMPointerUnfix. If you continue to use the pointer, repeat the original call to WOWGetVDMPointerFix to refresh the pointer. The drawback to this approach is that it cannot be used if the called function that yields the messaging system uses 32-bit pointers that you provide after yielding the messaging system. If you cannot determine if this will be a problem, the first approach would be a safer choice.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Page 99 of 119
CallProc32W
Use the CallProc32W function in 16-bit code to call an entry-point function in a 32-bit DLL. You cannot create a prototype for CallProc32W unless you do one of the following: Restrict each file so that it only uses calls to functions that contain the same number of parameters. Create a prototype CallProc32W_1 for functions that use one parameter, CallProc32W_2 for functions that use two parameters, and so forth. When linking your application or DLL, use forwarders to map calls to these functions to CallProc32W. This is a limitation of the Pascal calling convention. For this reason, you should use the CallProcEx32W function, which uses the C calling convention to support a variable number of arguments. DWORD FAR PASCAL CallProc32W( // parameter for DLL function DWORD param1, // parameter for DLL function DWORD param2, // up to 32 parameters for DLL function ... , lpProcAddress32, // the DLL function to be called LPVOID DWORD fAddressConvert, // bit mask // number of parameters passed DWORD nParams );
Parameters
param1 through param32 Parameters for the 32-bit procedure represented by lpProcAddress32. lpProcAddress32 A value corresponding to the procedure to be called, which is returned by the GetProcAddress32W function. fAddressConvert Bit mask representing which parameters will be treated as 16:16 pointers and translated into flat linear pointers
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
before being passed to the 32-bit procedure. The lowest bit in the mask represents the last parameter specified (paramN), the second lowest bit represents the second to the last parameter specified (paramN-1), and so on, so that the highest bit in the mask represents param1. nParams Number of DWORD parameters to be passed to the DLL function (param1 through paramN). For functions that take no parameters, this parameter will be zero. You can also specify the calling convention by using the OR operator to combine this value with one of the following constants: Value Meaning CPEX_DEST_STDCALL The function uses the standard-call calling convention. This is the default. CPEX_DEST_CDECL The function uses the C calling convention.
Return Value
Returns the return value from the 32-bit entry-point function represented by lpProcAddress32. The return value can also be zero under the following conditions: lpProcAddress32 is zero nParams is greater than 32 lpProcAddress32 returns zero
Remarks
CallProc32W takes at least three parameters: lpProcAddress32, fAddressConvert, and nParams. In addition, it can take a maximum of 32 optional parameters. These parameters must be DWORD types and must match the type that the 32-bit thunk DLL is expecting. If the appropriate bit is set in the fAddressConvert mask, the parameter will be translated from a 16:16 pointer to a 32-bit flat linear pointer. CallProc32W and CallProcEx32W do not automatically fix global memory handles that are translated to 0:32 pointers. Therefore, you must call the GlobalFix or GlobalWire function on the handle first and GlobalUnfix and GlobalUnwire afterward. Windows 95: Global compaction can move memory blocks at any time while the current thread is executing 32bit code. Because of this, not fixing segments before calling the target function works in Windows NT, but may cause race conditions in Windows 95. Note You should be careful when using this function, because there is no compiler check made on the number and type of parameters, no conversion of types (all parameters are passed as type DWORD and are passed directly to the function without conversion). No checks of the 16:16 address are made (limit checks, NULL checks, correct ring level, and so on).
See Also
CallProcEx32W, GetProcAddress32W
CallProcEx32W
Use the CallProcEx32W function in 16-bit code to call an entry-point function in a 32-bit DLL. CallProcEx32W is similar to CallProc32W, but it uses the C calling convention to allow a variable number of arguments.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
DWORD FAR CallProcEx32W( // number of parameters passed ....DWORD nParams, DWORD fAddressConvert, // bit mask DWORD lpProcAddress, // the DLL function to be called // parameter for DLL function DWORD param1 // up to 32 parameters for DLL function ... );
Parameters
nParams Number of DWORD parameters to be passed to the DLL function (param1 through paramN). For functions that take no parameters, this parameter will be zero. You can also specify the calling convention by using the OR operator to combine this value with one of the following constants: Value Meaning CPEX_DEST_STDCALL The function uses the standard-call calling convention. This is the default. CPEX_DEST_CDECL The function uses the C calling convention. fAddressConvert Bit mask representing which parameters will be treated as 16:16 pointers and translated into flat linear pointers before being passed to the 32-bit procedure. The lowest bit in the mask represents the first parameter specified (param1), the second lowest bit represents the second to the last parameter specified (param2), and so on, so that the highest bit in the mask represents paramN. lpProcAddress A value corresponding to the procedure to be called, which is returned by the GetProcAddress32W function. param1 through param32 Parameters for the 32-bit procedure represented by lpProcAddress
Return Value
Returns the return value from the 32-bit entry-point function represented by lpProcAddress. The return value can also be zero under the following conditions: lpProcAddress is zero nParams is greater than 32 lpProcAddress returns zero
Remarks
CallProc32W and CallProcEx32W do not automatically fix global memory handles that are translated to 0:32 pointers. Therefore, you must call the GlobalFix or GlobalWire function on the handle first and GlobalUnfix and GlobalUnwire afterward. Windows 95: Global compaction can move memory blocks at any time while the current thread is executing 32-
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
bit code. Because of this, not fixing segments before calling the target function works in Windows NT, but may cause race conditions in Windows 95.
See Also
CallProc32W, GetProcAddress32W
FreeLibrary32W
Use the FreeLibrary32W function in 16-bit code to free a 32-bit thunk DLL that it had previously loaded with the LoadLibraryEx32W function. BOOL FAR PASCAL FreeLibrary32W( DWORD hInst // handle to loaded library module );
Parameters
hInst Identifies the loaded library module. Returned by LoadLibraryEx32W.
Return Value
Returns TRUE if successful or FALSE otherwise.
Remarks
The system does not do any cleanup of 32-bit thunk DLLs when the 16-bit application exits. The 16-bit application or DLL must free the 32-bit thunk DLL when it is finished using it. Windows 95: This function causes Windows 95 to release the Win16Mutex. If this function is called from a 16-bit DLL, it can be reentered as soon as the 32-bit DLL entry-point function is called. This happens when another 32bit process thunks to the 16-bit DLL or when another 16-bit DLL calls this 16-bit DLL. However, if this function is called in a 16-bit application and the 32-bit DLL entry-point function does not yield, the function is not reentered.
See Also
LoadLibraryEx32W
GetProcAddress32W
Use the GetProcAddress32W in 16-bit code retrieve a value that represents a function in a 32-bit DLL. DWORD FAR PASCAL GetProcAddress32W( // handle to loaded library module DWORD hInst, LPCSTR lpszProc // name of function
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
);
Parameters
hModule Identifies the loaded library module that contains the function. The LoadLibraryEx32W function returns this handle. lpszProc Points to a null-terminated string containing the function name.
Return Value
Returns a 32-bit value if successful. This value must be passed as a parameter to the CallProc32W or CallProcEx32W function rather than being used directly.
Remarks
Windows 95: This function causes Windows 95 to release the Win16Mutex. If this function is called from a 16-bit DLL, it can be reentered as soon as the 32-bit DLL entry-point function is called. This happens when another 32bit process thunks to the 16-bit DLL or when another 16-bit DLL calls this 16-bit DLL. However, if this function is called in a 16-bit application and the 32-bit DLL entry-point function does not yield, the function is not reentered.
See Also
CallProc32W, CallProcEx32W, LoadLibraryEx32W
GetVDMPointer32W
Use GetVDMPointer32W in 16-bit code to translate a 16:16 pointer into a 32-bit pointer. DWORD FAR PASCAL GetVDMPointer32W( LPVOID lpAddress, // 16:16 address // mode flag UINT fMode );
Parameters
lpAddress Valid protected or real mode 16:16 address. fMode One of the following flags: 1 The address is interpreted as a protected-mode address. 0 The address is interpreted as a real-mode address.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Remarks
On non-x86 platforms, real mode address 0:0 may not point to linear 0 in memory, so always use GetVDMPointer32W to avoid making assumptions about memory layout. The memory manager moves segments in linear memory, but keeps the selectors the same. However, if you get the linear address of a block, it may not be valid if the 16-bit global memory manager moves the block the selector points to. Windows 95: You should assume that global compaction can occur any time that a generic thunk is entered, a Win32 function is called, or the current application yields.
LoadLibraryEx32W
Use the LoadLibraryEx32W function in 16-bit code to load a 32-bit DLL. DWORD FAR PASCAL LoadLibraryEx32W( LPCSTR lpszLibFile, // points to name of executable module // reserved, must be NULL DWORD hFile, // entry-point execution flag DWORD dwFlags );
Parameters
lpszLibFile Points to a null-terminated string that names a Win32-based DLL module. hFile This parameter is reserved for future use. It must be NULL. dwFlags Specifies the action to take when loading the module. This parameter can be one of the following values: DONT_RESOLVE_DLL_REFERENCES LOAD_LIBRARY_AS_DATAFILE LOAD_WITH_ALTERED_SEARCH_PATH For more information on these values, see LoadLibraryEx.
Return Value
If the function succeeds, the return value is a 32-bit handle to a DLL module. If the function fails, the return value is NULL.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction Remarks
After calling this function, the 16-bit thunk DLL can call the GetProcAddress32W function to get the address of the 32-bit entrypoint function(s) and then call the thunk(s) by using the CallProc32W or CallProcEx32W function. Windows 95: This function causes Windows 95 to release the Win16Mutex. If this function is called from a 16-bit DLL, it can be reentered as soon as the 32-bit DLL entry-point function is called. This happens when another 32bit process thunks to the 16-bit DLL or when another 16-bit DLL calls this 16-bit DLL. However, if this function is called in a 16-bit application and the 32-bit DLL entry-point function does not yield, the function is not reentered.
See Also
CallProc32W, CallProcEx32W, GetProcAddress32W
WOWCallback16
Use the WOWCallback16 function in 32-bit code called from 16-bit code (through generic thunks) to call back to the 16-bit side (generic callback). DWORD WINAPI WOWCallback16( DWORD vpfn16, // pointer to callback function DWORD dwParam // parameter for callback function );
Parameters
vpfn16 A 16:16 pointer to 16-bit callback routine, passed from the 16-bit side. dwParam
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Parameter for the 16-bit callback routine. If this value is a pointer, it can be used as either a 16:16 or 0:32 pointer, as long as both sides agree on the semantics.
Return Value
The return value comes from the callback routine. If the callback routine returns a WORD type instead of a DWORD type, the upper 16 bits of the return value are undefined and should be ignored by using LOWORD (dwRetCode). If the callback routine has no return value, the entire return value of this function is undefined.
Remarks
The 16-bit function to be called must be declared with one of the following types. DWORD FAR PASCAL CallbackRoutine(DWORD dwParam); DWORD FAR PASCAL CallbackRoutine(VOID FAR *vp); The type used is determined by whether the parameter is a pointer. If you are passing a pointer, you will need to get the pointer by using either the WOWGlobalAlloc16 or WOWGlobalAllocLock16 function.
See Also
LOWORD, WOWGlobalAlloc16, WOWGlobalAllocLock16
WOWCallback16Ex
Use the WOWCallback16Ex function in 32-bit code called from 16-bit code (through generic thunks) to call back to the 16-bit side (generic callback). BOOL WINAPI WOWCallback16Ex( // pointer to callback function DWORD vpfn16, // flags DWORD dwFlags, cbArgs, // byte count of pArgs arguments DWORD // arguments for callback function PVOID pArgs, PDWORD pdwRetCode // callback function return code );
Parameters
vpfn16 A 16:16 pointer to 16-bit callback routine, passed from the 16-bit side. dwFlags One of the following flags: WCB16_CDECL Calls a _cdecl callback routine. WCB16_PASCAL Calls a _pascal callback routine (default).
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
cbArgs Count of bytes in arguments (used to properly clean the 16-bit stack). pArgs Arguments for the callback routine. pdwRetCode Receives the return code from the callback routine.
Return Value
If cbArgs is larger than the WCB16_MAX_ARGS bytes that the system supports, the return value is FALSE and the GetLastError function returns the ERROR_INVALID_PARAMETER value. Otherwise, the return value is TRUE and the DWORD pointed to by pdwRetCode contains the return code from the callback routine. If the callback routine returns a WORD type instead of a DWORD type, the upper 16 bits of the return code are undefined and should be ignored by using LOWORD(dwRetCode).
Remarks
WOWCallback16Ex allows any combination of arguments up to WCB16_MAX_CBARGS bytes total to be passed to the 16-bit callback routine. Regardless of the value of cbArgs, WCB16_MAX_CBARGS bytes will always be copied from pArgs to the 16-bit stack. If pArgs is less than WCB16_MAX_CBARGS bytes from the end of a page and the next page is inaccessible, WOWCallback16Ex will incur an access violation. The arguments pointed to by pArgs must be in the correct order for the callback routines calling convention. For example, to call a Pascal routine, place the arguments in the pArgs array in reverse order, with the least significant word first for DWORD types and offset first for FAR pointers. When you call a _cdecl routine, place the arguments in the pArgs array in the order listed in the function prototype with the least significant word first for DWORD types and offset first for FAR pointers.
See Also
LOWORD
WOWGetVDMPointer
The WOWGetVDMPointer function converts a 16:16 address to the equivalent linear address. LPVOID WINAPI WOWGetVDMPointer( // 16:16 address DWORD vp, // size of vp block DWORD dwBytes, BOOL fProtectedMode // protected mode flag );
Parameters
vp
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Valid 16:16 address. dwBytes Size of the block pointed to by vp. fProtectedMode
One of the following flags: 1 The upper 16 bits are treated as a selector in the local descriptor table (16-bit protected mode pointer). 0 The upper 16 bits are treated as a real-mode segment value (real-mode 16:16 pointer).
Return Value
Returns a 32-bit address if successful. If the function is invalid, the return value is NULL.
Remarks
Windows NT: Limit checking is performed only in the checked (debugging) build of WOW32.DLL, which will cause NULL to be returned when the limit is exceeded by the supplied offset. Windows 95: This function should never be used on a 16-bit global memory handle selector that has not been previously fixed in memory by using the GlobalFix or GlobalWire function. You should assume that global compaction can occur at any time the Win16Mutex is not owned by the current thread.
WOWGetVDMPointerFix
The WOWGetVDMPointerFix function converts a 16:16 address to the equivalent linear address. Windows 95: This function calls the GlobalFix function before returning the linear address so that the 16-bit memory block will not be moved around in the 16-bit global heap. Windows NT: This function behaves like the WOWGetVDMPointer function. The memory is not fixed. LPVOID WINAPI WOWGetVDMPointerFix( // 16:16 address DWORD vp, // size of vp block DWORD dwBytes, BOOL fProtectedMode // protected mode flag );
Parameters
vp Valid 16:16 address. dwBytes Size of the block pointed to by vp.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
fProtectedMode
One of the following flags: 1 The upper 16 bits are treated as a selector in the local descriptor table (16-bit protected mode pointer). 0 The upper 16 bits are treated as a real-mode segment value (real-mode 16:16 pointer).
Return Value
Returns a 32-bit address if successful. If the selector is invalid, the return value is NULL.
See Also
WOWGetVDMPointer
WOWGetVDMPointerUnfix
Windows 95: The WOWGetVDMPointerUnfix function uses the GlobalUnfix function to unfix a pointer retrieved by the WOWGetVDMPointerFix function. Windows NT: This function has no effect. VOID WINAPI WOWGetVDMPointerUnfix( LPCSTR vp // 32-bit linear address );
Parameters
vp Address retrieved by the WOWGetVDMPointerFix function.
Return Value
This function does not return a value.
See Also
WOWGetVDMPointerFix
WOWGlobalAlloc16
The WOWGlobalAlloc16 function allocates the specified number of bytes from the 16-bit global heap. WORD WINAPI WOWGlobalAlloc16( WORD wFlags, // object allocation attributes // number of bytes to allocate DWORD cb
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
);
Parameters
wFlags Specifies how to allocate memory. This parameter can be a combination of the following values: GHND, GMEM_DDESHARE, GMEM_DISCARDABLE, GMEM_FIXED, GMEM_LOWER, GMEM_MOVEABLE, GMEM_NOCOMPACT, GMEM_NODISCARD, GMEM_NOT_BANKED, GMEM_NOTIFY, GMEM_SHARE, GMEM_ZEROINIT, and GPTR. cb Specifies the number of bytes to allocate.
Return Value
Returns the handle of the newly allocated memory object if successful. Otherwise, returns NULL.
See Also
WOWGlobalLock16
WOWGlobalAllocLock16
The WOWGlobalAllocLock16 function combines the functionality of the WOWGlobalAlloc16 and WOWGlobalLock16 functions. DWORD WINAPI WOWGlobalAllocLock16( WORD wFlags, // object allocation flags // number of bytes to allocate DWORD cb, LPWORD phMem // handle to global memory object );
Parameters
wFlags Specifies how to allocate memory. This parameter can be a combination of the following values: GHND, GMEM_DDESHARE, GMEM_DISCARDABLE, GMEM_FIXED, GMEM_LOWER, GMEM_MOVEABLE, GMEM_NOCOMPACT, GMEM_NODISCARD, GMEM_NOT_BANKED, GMEM_NOTIFY, GMEM_SHARE, GMEM_ZEROINIT, and GPTR. cb Specifies the number of bytes to allocate. phMem Handle to the object in the 16-bit global heap. This value is returned by WOWGlobalAllocLock16.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Remarks
The pointer returned is a 16:16 pointer that cannot be dereferenced directly in 32-bit code. Instead, call the WOWGetVDMPointerFix function.
See Also
WOWGetVDMPointerFix, WOWGlobalAlloc16, WOWGlobalLock16
WOWGlobalFree16
The WOWGlobalFree16 function frees the specified global memory object. WORD WINAPI WOWGlobalFree16( WORD hMem // handle to the global memory object );
Parameters
hMem Handle to the object in the 16-bit global heap. This value must have been obtained from the WOWGlobalAlloc16 or WOWGlobalAllocLock16 function.
Return Value
Returns NULL if successful.
See Also
WOWGlobalAlloc16, WOWGlobalAllocLock16
WOWGlobalLock16
The WOWGlobalLock16 function locks a global memory object and returns a pointer to the first byte of the objects memory block.. DWORD WINAPI WOWGlobalLock16( WORD hMem // handle to the global memory object );
Parameters
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
hMem
Handle to the object in the 16-bit global heap. This value must have been obtained from the WOWGlobalAlloc16 or WOWGlobalAllocLock16 function.
Return Value
Returns a pointer to the first byte of the objects memory block if successful. Otherwise, returns NULL.
Remarks
The pointer returned is a 16:16 pointer that cannot be dereferenced directly in 32-bit code. Instead, call the WOWGetVDMPointerFix function.
See Also
WOWGetVDMPointerFix, WOWGlobalAlloc16, WOWGlobalAllocLock16
WOWGlobalLockSize16
The WOWGlobalLockSize16 function combines the functionality of the WOWGlobalLock16 and 16-bit GlobalSize functions. DWORD WINAPI WOWGlobalLockSize16( WORD hMem, // handle to the global memory object PDWORD pcb // gets size of the global memory object );
Parameters
hMem Handle to the object in the 16-bit global heap. This value must have been obtained from the WOWGlobalAlloc16 or WOWGlobalAllocLock16 function. pcb Receives the size of the object in the 16-bit global heap.
Return Value
Returns a pointer to the first byte of the memory block if successful. Otherwise, returns NULL.
See Also
WOWGlobalAlloc16, WOWGlobalAllocLock16, WOWGlobalLock16
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
WOWGlobalUnlock16
The WOWGlobalUnlock16 function unlocks a global memory object. BOOL WINAPI WOWGlobalUnlock16( WORD hMem // handle to the global memory object );
Parameters
hMem Handle to the object in the 16-bit global heap. This value must have been obtained from the WOWGlobalAlloc16 or WOWGlobalAllocLock16 function.
Return Value
Returns zero if the objects lock count was decremented (decreased by one) to zero. Otherwise, returns a nonzero value.
WOWGlobalUnlockFree16
The WOWGlobalUnlockFree16 function combines the functionality of the WOWGlobalUnlock16 and WOWGlobalFree16 functions. WORD WINAPI WOWGlobalUnlockFree16( DWORD vpMem // address of memory block );
Parameters
vpMem Address of memory block returned by the WOWGlobalLock16 or WOWGlobalAllocLock16 function.
Return Value
Returns NULL if successful.
See Also
WOWGlobalAllocLock16, WOWGlobalFree16, WOWGlobalLock16, WOWGlobalUnlock16
WOWHandle16
The WOWHandle16 function is used to map a 32-bit handle to a 16-bit handle. Because the relationship between
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
a Win16 handle and a Win32 handle may change in the future, use this function to convert handles instead of any knowledge of the relationship between them. WORD WINAPI WOWHandle16( // 32-bit handle HANDLE Handle, WOW_HANDLE_TYPE Type // handle type );
Parameters
Handle The 32-bit handle to be mapped. Type Indicates the type of handle being translated. The accepted values are of the form WOW_TYPE_handle where handle can be HWND, HMENU, HDWP, HDROP, HDC, HFONT, HMETAFILE, HRGN, HBITMAP, HBRUSH, HPALETTE, HPEN, HACCEL, and HTASK. For example, use WOW_TYPE_HWND to convert an HWND.
Return Value
A 16-bit handle.
Remarks
You can also use supplied macros to map handles. For example, to map a 32-bit HWND to a 16-bit HWND, you would use the HWND_16 macro. (hWnd16 = HWND_16(hWnd32)) WOWHandle16 with WOW_TYPE_HTASK (and HTASK_16) takes a thread identifier and converts it to a handle to a task if possible.
WOWHandle32
The WOWHandle32 function is used to map a 16-bit handle to a 32-bit handle. Because the relationship between a Win16 handle and a Win32 handle may change in the future, use this function to convert handles instead of any knowledge of the relationship between them. HANDLE WINAPI WOWHandle32( // 16-bit handle WORD Handle, WOW_HANDLE_TYPE Type // handle type );
Parameters
Handle The 16-bit handle to be mapped.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Type
Indicates the type of handle being translated. The accepted values are of the form WOW_TYPE_handle where handle can be HWND, HMENU, HDWP, HDROP, HDC, HFONT, HMETAFILE, HRGN, HBITMAP, HBRUSH, HPALETTE, HPEN, HACCEL, HTASK, and FULLHWND. For example, use WOW_TYPE_HWND to convert an HWND.
Return Value
A 32-bit handle.
Remarks
You can also use supplied macros to map handles. For example, to map a 16-bit HWND to a 32-bit HWND, you would use the HWND_32 macro. (hWnd32 = HWND_32(hWnd16)) The type WOW_TYPE_FULLHWND is a window handle that the system passes to a Win32-based application. The type WOW_TYPE_HWND has a different value, but it is recognized by the system and may be passed as a parameter to Win32 functions. If you intend to store the window handle and use it in comparisions with 32-bit window handles received from Win32 functions, use WOW_TYPE_FULLHWND when calling WOWHandle32. Do not make assumptions about the relationship between the 16-bit window handle, the 32-bit window handle, and the full window handle. This relationship has changed in the past (for performance reasons), and it may change again in the future. When you pass WOWHandle32 type WOW_TYPE_HTASK with a 16-bit task handle, it returns a 32-bit thread identifier. You may compare this value with other thread identifiers, such as those returned by the GetWindowThreadProcessId function.
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Shortcut Text Win32 Application Programming Interface Writing Great Win32-based Applications The Generic Win32-based Application Overview of the Build Process Installing Applications WINDOWS.H and STRICT Type Checking Porting Code From 16-bit Windows to 32-bit Windows Handling Messages with Portable Macros Generic Thunks Windows 95 System Limitations Window Management Window Controls Shell Features Graphics Device Interface System Services International Features Network Services File Information Long Filenames Context Menus Icons Shortcuts Clipboard Data Transfer Operations Common Controls and Dialog Boxes Palette Windows Help Multiple Views Pen Input Installing Applications The entry-point function The menu The window procedure The About dialog box Source Code Registering the window class
Internet Address file:///C:/WINDOWS/TEMP/win32api.htm file:///C:/win32/95guide/src/greatapp.htm file:///C:/WINDOWS/TEMP/generic.htm file:///C:/WINDOWS/TEMP/buildw.htm file:///C:/win32/95guide/src/setup.htm file:///C:/WINDOWS/TEMP/ch8stric.htm file:///C:/WINDOWS/TEMP/cc5port.htm file:///C:/WINDOWS/TEMP/ch6msg.htm file:///C:/WINDOWS/TEMP/genthunk.htm javascript:document.x.iv.ALink( file:///C:/WINDOWS/TEMP/win32api_2.htm file:///C:/WINDOWS/TEMP/win32api_3.htm file:///C:/WINDOWS/TEMP/win32api_4.htm file:///C:/WINDOWS/TEMP/win32api_5.htm file:///C:/WINDOWS/TEMP/win32api_6.htm file:///C:/WINDOWS/TEMP/win32api_7.htm file:///C:/WINDOWS/TEMP/win32api_8.htm file:///C:/WINDOWS/TEMP/greatapp_2.htm file:///C:/WINDOWS/TEMP/greatapp_3.htm file:///C:/WINDOWS/TEMP/greatapp_4.htm file:///C:/WINDOWS/TEMP/greatapp_5.htm file:///C:/WINDOWS/TEMP/greatapp_6.htm file:///C:/WINDOWS/TEMP/greatapp_7.htm file:///C:/WINDOWS/TEMP/greatapp_8.htm file:///C:/WINDOWS/TEMP/greatapp_11.htm file:///C:/WINDOWS/TEMP/greatapp_12.htm file:///C:/WINDOWS/TEMP/greatapp_13.htm file:///C:/WINDOWS/TEMP/greatapp_14.htm file:///C:/WINDOWS/TEMP/setup.htm file:///C:/WINDOWS/TEMP/generic_1.htm file:///C:/WINDOWS/TEMP/generic_5.htm file:///C:/WINDOWS/TEMP/generic_6.htm file:///C:/WINDOWS/TEMP/generic_7.htm file:///C:/WINDOWS/TEMP/generic_8.htm file:///C:/WINDOWS/TEMP/generic_2.htm
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Shortcut Text Creating the main window Entering the message loop Dialog Resource GENERIC.C GENERIC.H GENERIC.RC GENERIC.DLG Managing Memory Managing File Operations Managing Processes Setting Targets Compiling Source Files Building Applications Building DLLs Using the C Run-Time Library Adding Entries to the Registry New types and macros Using STRICT to improve type checking #define Making Your Application STRICT Compliant Overview of Changes Porting Your Application Using PORTTOOL to Automate Porting Additional Porting Work Revising the Window Procedure Declaration Using Proper Data Types Handling Messages Adjusting Function Calls Revising the WinMain Function Revising Dynamic-Link Libraries Graphics functions Functions accessing extra window data MS-DOS system calls Far-pointer functions Functions getting list and combo box contents
Internet Address file:///C:/WINDOWS/TEMP/generic_3.htm file:///C:/WINDOWS/TEMP/generic_4.htm file:///C:/tools/src/rc_37.htm file:///C:/WINDOWS/TEMP/generic_9.htm file:///C:/WINDOWS/TEMP/generic_10.htm file:///C:/WINDOWS/TEMP/generic_11.htm file:///C:/WINDOWS/TEMP/generic_12.htm file:///C:/WINDOWS/TEMP/09high_2.htm file:///C:/WINDOWS/TEMP/09high_3.htm file:///C:/WINDOWS/TEMP/09high_4.htm file:///C:/WINDOWS/TEMP/buildw_2.htm file:///C:/WINDOWS/TEMP/buildw_3.htm file:///C:/WINDOWS/TEMP/buildw_4.htm file:///C:/WINDOWS/TEMP/buildw_5.htm file:///C:/WINDOWS/TEMP/buildw_6.htm file:///C:/WINDOWS/TEMP/setup_11.htm file:///C:/WINDOWS/TEMP/ch8stric_1.htm file:///C:/WINDOWS/TEMP/ch8stric_5.htm file:///C:/tools/src/rc_68.htm file:///C:/WINDOWS/TEMP/ch8stric_7.htm file:///C:/WINDOWS/TEMP/cc5port_1.htm file:///C:/WINDOWS/TEMP/cc5port_2.htm file:///C:/WINDOWS/TEMP/cc5port_21.htm file:///C:/WINDOWS/TEMP/cc5port_22.htm file:///C:/WINDOWS/TEMP/cc5port_3.htm file:///C:/WINDOWS/TEMP/cc5port_4.htm file:///C:/WINDOWS/TEMP/cc5port_5.htm file:///C:/WINDOWS/TEMP/cc5port_10.htm file:///C:/WINDOWS/TEMP/cc5port_17.htm file:///C:/WINDOWS/TEMP/cc5port_20.htm file:///C:/WINDOWS/TEMP/cc5port_11.htm file:///C:/WINDOWS/TEMP/cc5port_12.htm file:///C:/WINDOWS/TEMP/cc5port_13.htm file:///C:/WINDOWS/TEMP/cc5port_15.htm file:///C:/WINDOWS/TEMP/cc5port_16.htm
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Shortcut Text Initializing Instances Accessing the Command Line Through lpCmdLine Profile Strings and .INI Files Focus, Mouse Capture, and Localized Input Shared Graphical Objects Memory and Pointers Structure Alignment Ranges and Promotions Using message crackers Writing message crackers for user-defined messages Adapting message crackers to special cases Using control message functions Handling Special Cases of Messages Dialog Procedures Window Subclassing Window Instance Data Process Context Declaring the DLL function Loading the Win32-based DLL Getting the address of the DLL function Calling the DLL function Freeing the Win32-based DLL WOWCallback16 Translating 16:16 Pointers LoadLibraryEx32W GetProcAddress32W CallProcEx32W CallProc32W WOWHandle32 FreeLibrary32W GetVDMPointer32W WOWGetVDMPointer WOWGetVDMPointerFix WOWGetVDMPointerUnfix WOWCallback16Ex
Internet Address file:///C:/WINDOWS/TEMP/cc5port_18.htm file:///C:/WINDOWS/TEMP/cc5port_19.htm file:///C:/WINDOWS/TEMP/cc5port_23.htm file:///C:/WINDOWS/TEMP/cc5port_24.htm file:///C:/WINDOWS/TEMP/cc5port_25.htm file:///C:/WINDOWS/TEMP/cc5port_26.htm file:///C:/WINDOWS/TEMP/cc5port_27.htm file:///C:/WINDOWS/TEMP/cc5port_28.htm file:///C:/WINDOWS/TEMP/ch6msg_1.htm file:///C:/WINDOWS/TEMP/ch6msg_8.htm file:///C:/WINDOWS/TEMP/ch6msg_9.htm file:///C:/WINDOWS/TEMP/ch6msg_13.htm file:///C:/WINDOWS/TEMP/ch6msg_7.htm file:///C:/WINDOWS/TEMP/ch6msg_10.htm file:///C:/WINDOWS/TEMP/ch6msg_11.htm file:///C:/WINDOWS/TEMP/ch6msg_12.htm file:///C:/WINDOWS/TEMP/genthunk_2.htm file:///C:/WINDOWS/TEMP/genthunk_5.htm file:///C:/WINDOWS/TEMP/genthunk_6.htm file:///C:/WINDOWS/TEMP/genthunk_7.htm file:///C:/WINDOWS/TEMP/genthunk_8.htm file:///C:/WINDOWS/TEMP/genthunk_9.htm file:///C:/WINDOWS/TEMP/genthunk_20.htm file:///C:/WINDOWS/TEMP/genthunk_10.htm file:///C:/WINDOWS/TEMP/genthunk_18.htm file:///C:/WINDOWS/TEMP/genthunk_16.htm file:///C:/WINDOWS/TEMP/genthunk_14.htm file:///C:/WINDOWS/TEMP/genthunk_13.htm file:///C:/WINDOWS/TEMP/genthunk_33.htm file:///C:/WINDOWS/TEMP/genthunk_15.htm file:///C:/WINDOWS/TEMP/genthunk_17.htm file:///C:/WINDOWS/TEMP/genthunk_22.htm file:///C:/WINDOWS/TEMP/genthunk_23.htm file:///C:/WINDOWS/TEMP/genthunk_24.htm file:///C:/WINDOWS/TEMP/genthunk_21.htm
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002
Introduction
Shortcut Text WOWGlobalAlloc16 WOWGlobalAllocLock16 WOWGlobalFree16 WOWGlobalLock16 WOWGlobalLockSize16 WOWGlobalUnlock16 WOWGlobalUnlockFree16 WOWHandle16
Internet Address file:///C:/WINDOWS/TEMP/genthunk_25.htm file:///C:/WINDOWS/TEMP/genthunk_26.htm file:///C:/WINDOWS/TEMP/genthunk_27.htm file:///C:/WINDOWS/TEMP/genthunk_28.htm file:///C:/WINDOWS/TEMP/genthunk_29.htm file:///C:/WINDOWS/TEMP/genthunk_30.htm file:///C:/WINDOWS/TEMP/genthunk_31.htm file:///C:/WINDOWS/TEMP/genthunk_32.htm
file://C:\WINDOWS\TEMP\005861a4.htm
3/28/2002